-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
642e24e
commit 5e05cda
Showing
76 changed files
with
1,530 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
* | ||
!package.json | ||
!lib/**/*.js | ||
!index.js | ||
!index.d.ts | ||
!*.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# `@knexion/filter` | ||
|
||
> TODO: description | ||
## Usage | ||
|
||
``` | ||
const filter = require('@knexion/filter'); | ||
// TODO: DEMONSTRATE API | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './lib'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/** @type {import('ts-jest').JestConfigWithTsJest} */ | ||
module.exports = { | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './interceptors'; | ||
export * from './interfaces'; |
42 changes: 42 additions & 0 deletions
42
packages/filter/lib/interceptors/filter-by-array.interceptor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { Observable } from 'rxjs'; | ||
import { | ||
addPrefixColumn, | ||
ExecutionContext, | ||
RepositoryInterceptor, | ||
RepositoryInterceptorNext, | ||
SelectDatabaseOptions, | ||
} from '@knexion/core'; | ||
import { FilterOptions } from '../interfaces'; | ||
|
||
type FilterByArrayOperator = 'in' | string; | ||
|
||
export class FilterByArrayInterceptor<TRecord, TResult> | ||
implements RepositoryInterceptor<TRecord, TResult> | ||
{ | ||
constructor( | ||
private readonly name: keyof TRecord, | ||
private readonly value: string[], | ||
private readonly operator: FilterByArrayOperator = 'in', | ||
private readonly options: FilterOptions = {}, | ||
) {} | ||
|
||
public intercept( | ||
context: ExecutionContext< | ||
TRecord, | ||
TResult, | ||
SelectDatabaseOptions<TRecord, TResult> | ||
>, | ||
next: RepositoryInterceptorNext, | ||
): Observable<unknown> { | ||
const { useAlias = true } = this.options; | ||
const column = useAlias | ||
? addPrefixColumn(this.name as string, context.options.alias) | ||
: (this.name as string); | ||
if (this.operator === 'in') { | ||
context.queryBuilder.whereIn(column, this.value); | ||
} else { | ||
context.queryBuilder.where(column, this.operator, this.value); | ||
} | ||
return next.handle(); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
packages/filter/lib/interceptors/filter-by-number-range.interceptor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { Observable } from 'rxjs'; | ||
import { | ||
addPrefixColumn, | ||
ExecutionContext, | ||
RepositoryInterceptor, | ||
RepositoryInterceptorNext, | ||
SelectDatabaseOptions, | ||
} from '@knexion/core'; | ||
import { buildRangeNumberFilter } from '../utils'; | ||
import { FilterOptions, RangeNumberFilter } from '../interfaces'; | ||
|
||
export class FilterByNumberRangeInterceptor<TRecord, TResult> | ||
implements RepositoryInterceptor<TRecord, TResult> | ||
{ | ||
constructor( | ||
private readonly name: keyof TRecord, | ||
private readonly value: RangeNumberFilter, | ||
private readonly options: FilterOptions = {}, | ||
) {} | ||
public intercept( | ||
context: ExecutionContext< | ||
TRecord, | ||
TResult, | ||
SelectDatabaseOptions<TRecord, TResult> | ||
>, | ||
next: RepositoryInterceptorNext, | ||
): Observable<unknown> { | ||
const { useAlias = true } = this.options; | ||
const column = useAlias | ||
? addPrefixColumn(this.name as string, context.options.alias) | ||
: (this.name as string); | ||
buildRangeNumberFilter(context.queryBuilder, column, this.value); | ||
return next.handle(); | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
packages/filter/lib/interceptors/filter-timestamp.interceptor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { Observable } from 'rxjs'; | ||
import { Knex } from 'knex'; | ||
import { | ||
addPrefixColumn, | ||
ExecutionContext, | ||
RepositoryInterceptor, | ||
RepositoryInterceptorNext, | ||
SelectDatabaseOptions, | ||
} from '@knexion/core'; | ||
import { RangeNumberFilter, TimestampFilter } from '../interfaces'; | ||
|
||
export class FilterTimestampInterceptor<TRecord, TResult> | ||
implements RepositoryInterceptor<TRecord, TResult> | ||
{ | ||
constructor(private readonly timestampField: keyof TRecord) {} | ||
|
||
public intercept( | ||
context: ExecutionContext< | ||
TRecord, | ||
TResult, | ||
SelectDatabaseOptions<TRecord, TResult> | ||
>, | ||
next: RepositoryInterceptorNext, | ||
): Observable<unknown> { | ||
if (!context.options[this.timestampField as string]) { | ||
return next.handle(); | ||
} | ||
const timestampFilter = context.options[this.timestampField as string]; | ||
if (this.isNumber(timestampFilter)) { | ||
context.queryBuilder.where( | ||
addPrefixColumn('created_at', context.options.alias), | ||
timestampFilter, | ||
); | ||
} else { | ||
this.buildComplexDateFilterQuery( | ||
context.queryBuilder, | ||
timestampFilter, | ||
context.options, | ||
); | ||
} | ||
return next.handle(); | ||
} | ||
|
||
private isNumber(dateFilter: number | TimestampFilter): dateFilter is number { | ||
return typeof dateFilter === 'number'; | ||
} | ||
|
||
private buildComplexDateFilterQuery( | ||
queryBuilder: Knex.QueryBuilder<TRecord, TResult>, | ||
dateFilter: RangeNumberFilter, | ||
options: SelectDatabaseOptions<TRecord, TResult>, | ||
): void { | ||
Object.entries(dateFilter).forEach(([operator, value]) => | ||
this.getQueryForDateOperator( | ||
queryBuilder, | ||
operator as 'gt' | 'gte' | 'lt' | 'lte', | ||
value, | ||
options.alias, | ||
), | ||
); | ||
} | ||
|
||
private getQueryForDateOperator( | ||
queryBuilder: Knex.QueryBuilder<TRecord, TResult>, | ||
operator: 'gt' | 'gte' | 'lt' | 'lte', | ||
value: number, | ||
alias?: string, | ||
): void { | ||
const createdAtColumnName = addPrefixColumn('created_at', alias); | ||
if (operator === 'gt') { | ||
queryBuilder.where(createdAtColumnName, '>', value); | ||
} else if (operator === 'gte') { | ||
queryBuilder.where(createdAtColumnName, '>=', value); | ||
} else if (operator === 'lt') { | ||
queryBuilder.where(createdAtColumnName, '<', value); | ||
} else if (operator === 'lte') { | ||
queryBuilder.where(createdAtColumnName, '<=', value); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Observable } from 'rxjs'; | ||
import { | ||
addPrefixColumn, | ||
ExecutionContext, | ||
RepositoryInterceptor, | ||
RepositoryInterceptorNext, | ||
SelectDatabaseOptions, | ||
} from '@knexion/core'; | ||
import { FilterObject, FilterObjectOptions } from '../interfaces'; | ||
import { isPlainObject } from '@nestjs/common/utils/shared.utils'; | ||
|
||
export class FilterInterceptor<TRecord, TResult> | ||
implements RepositoryInterceptor<TRecord, TResult> | ||
{ | ||
constructor(private readonly options: FilterObjectOptions = {}) {} | ||
|
||
public intercept( | ||
context: ExecutionContext< | ||
TRecord, | ||
TResult, | ||
SelectDatabaseOptions<TRecord, TResult> | ||
>, | ||
next: RepositoryInterceptorNext, | ||
): Observable<unknown> { | ||
const filterObject = context.options[this.options.optionKey ?? 'filter']; | ||
if (isPlainObject(filterObject)) { | ||
context.queryBuilder.where( | ||
this.appendAliasToFilterColumns( | ||
filterObject as FilterObject<TRecord>, | ||
context.options.alias, | ||
), | ||
); | ||
} | ||
|
||
return next.handle(); | ||
} | ||
|
||
private appendAliasToFilterColumns( | ||
filter: Record<string, unknown>, | ||
alias?: string, | ||
): Record<string, unknown> { | ||
return Object.fromEntries( | ||
Object.entries(filter).map(([name, value]) => { | ||
const { useAlias = true } = this.options; | ||
const column = useAlias ? addPrefixColumn(name, alias) : name; | ||
return [column, value]; | ||
}), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from './filter.interceptor'; | ||
export * from './filter-by-array.interceptor'; | ||
export * from './filter-by-number-range.interceptor'; | ||
export * from './filter-timestamp.interceptor'; |
11 changes: 11 additions & 0 deletions
11
packages/filter/lib/interfaces/filter-options.interface.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export interface FilterOptions { | ||
useAlias?: boolean; | ||
} | ||
|
||
export type FilterObject<TRecord> = Partial< | ||
Record<keyof TRecord, string | number | null> | ||
>; | ||
|
||
export interface FilterObjectOptions extends FilterOptions { | ||
optionKey?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './filter-options.interface'; | ||
export * from './range-number-filter.interface'; | ||
export * from './timestamp-filter.interface'; |
21 changes: 21 additions & 0 deletions
21
packages/filter/lib/interfaces/range-number-filter.interface.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
export interface RangeNumberFilter { | ||
/** | ||
* Return records where the field is after this value. | ||
*/ | ||
gt?: number; | ||
|
||
/** | ||
* Return records where the field is after or equal to this value. | ||
*/ | ||
gte?: number; | ||
|
||
/** | ||
* Return records where the field is before this value. | ||
*/ | ||
lt?: number; | ||
|
||
/** | ||
* Return records where the field is before or equal to this value. | ||
*/ | ||
lte?: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { RangeNumberFilter } from './range-number-filter.interface'; | ||
|
||
export type TimestampFilter = number | RangeNumberFilter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { Knex } from 'knex'; | ||
import { RangeNumberFilter } from '../interfaces'; | ||
|
||
const getQueryForDateOperator = ( | ||
queryBuilder: Knex.QueryBuilder, | ||
name: string, | ||
operator: 'gt' | 'gte' | 'lt' | 'lte', | ||
value: number, | ||
): void => { | ||
if (operator === 'gt') { | ||
queryBuilder.where(name, '>', value); | ||
} else if (operator === 'gte') { | ||
queryBuilder.where(name, '>=', value); | ||
} else if (operator === 'lt') { | ||
queryBuilder.where(name, '<', value); | ||
} else if (operator === 'lte') { | ||
queryBuilder.where(name, '<=', value); | ||
} | ||
}; | ||
|
||
export const buildRangeNumberFilter = ( | ||
queryBuilder: Knex.QueryBuilder, | ||
name: string, | ||
numberFilter: RangeNumberFilter, | ||
): void => { | ||
Object.entries(numberFilter).forEach(([operator, value]) => | ||
getQueryForDateOperator( | ||
queryBuilder, | ||
name as string, | ||
operator as 'gt' | 'gte' | 'lt' | 'lte', | ||
value, | ||
), | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './build-range-number-filter'; |
Oops, something went wrong.