graphql-connections
Advanced tools
Comparing version 9.0.0 to 9.1.0
@@ -5,2 +5,3 @@ 'use strict'; | ||
var luxon = require('luxon'); | ||
var graphql = require('graphql'); | ||
@@ -625,2 +626,37 @@ var utilities = require('graphql/utilities'); | ||
/** | ||
* Given filter values in unix seconds, this will convert the filters to mysql timestamps | ||
*/ | ||
function castUnixSecondsFiltersToMysqlTimestamps(filterFieldsToCast, timezone = 'UTC', includeOffset = false, includeZone = false) { | ||
// tslint:disable-next-line: cyclomatic-complexity | ||
return (filter) => { | ||
if (filterFieldsToCast.includes(filter.field) && filter.value && filter.value !== 'null') { | ||
if (!isNumberOrString(filter.value)) { | ||
throw new Error(`Cannot parse timestamp filter: ${filter.field}`); | ||
} | ||
const filterValue = typeof filter.value === 'string' ? Number(filter.value) : filter.value; | ||
return { | ||
...filter, | ||
value: luxon.DateTime.fromSeconds(filterValue, { zone: timezone }).toSQL({ | ||
includeOffset, | ||
includeZone | ||
}) | ||
}; | ||
} | ||
return filter; | ||
}; | ||
} | ||
function isNumberOrString(value) { | ||
return ['number', 'string'].includes(typeof value); | ||
} | ||
/** | ||
* Run a number of filter transformers from left to right on an IFilter. | ||
*/ | ||
function compose(...transformers) { | ||
return (filter) => transformers.reduce((accum, transformer) => { | ||
return transformer(accum); | ||
}, filter); | ||
} | ||
var filter_transformers = { castUnixSecondsFiltersToMysqlTimestamps, compose }; | ||
const printInputType = (type) => { | ||
@@ -915,2 +951,3 @@ const fields = type.getFields(); | ||
exports.CursorEncoder = CursorEncoder; | ||
exports.FilterTransformers = filter_transformers; | ||
exports.Knex = KnexQueryBuilder; | ||
@@ -917,0 +954,0 @@ exports.KnexMySQL = KnexMySQLFullTextQueryBuilder; |
@@ -5,4 +5,5 @@ export { default as ConnectionManager } from './connection_manager'; | ||
export { default as CursorEncoder } from './cursor_encoder'; | ||
export { default as FilterTransformers } from './filter_transformers'; | ||
export { Knex, KnexMySQL } from './query_builder'; | ||
export * from './types'; | ||
export { typeDefs, resolvers, gqlTypes } from './graphql_schema'; |
@@ -0,1 +1,2 @@ | ||
import { DateTime } from 'luxon'; | ||
import { GraphQLScalarType, GraphQLError, valueFromAST, Kind, GraphQLInputObjectType, GraphQLList, GraphQLString, GraphQLInt } from 'graphql'; | ||
@@ -620,2 +621,37 @@ import { coerceInputValue } from 'graphql/utilities'; | ||
/** | ||
* Given filter values in unix seconds, this will convert the filters to mysql timestamps | ||
*/ | ||
function castUnixSecondsFiltersToMysqlTimestamps(filterFieldsToCast, timezone = 'UTC', includeOffset = false, includeZone = false) { | ||
// tslint:disable-next-line: cyclomatic-complexity | ||
return (filter) => { | ||
if (filterFieldsToCast.includes(filter.field) && filter.value && filter.value !== 'null') { | ||
if (!isNumberOrString(filter.value)) { | ||
throw new Error(`Cannot parse timestamp filter: ${filter.field}`); | ||
} | ||
const filterValue = typeof filter.value === 'string' ? Number(filter.value) : filter.value; | ||
return { | ||
...filter, | ||
value: DateTime.fromSeconds(filterValue, { zone: timezone }).toSQL({ | ||
includeOffset, | ||
includeZone | ||
}) | ||
}; | ||
} | ||
return filter; | ||
}; | ||
} | ||
function isNumberOrString(value) { | ||
return ['number', 'string'].includes(typeof value); | ||
} | ||
/** | ||
* Run a number of filter transformers from left to right on an IFilter. | ||
*/ | ||
function compose(...transformers) { | ||
return (filter) => transformers.reduce((accum, transformer) => { | ||
return transformer(accum); | ||
}, filter); | ||
} | ||
var filter_transformers = { castUnixSecondsFiltersToMysqlTimestamps, compose }; | ||
const printInputType = (type) => { | ||
@@ -908,2 +944,2 @@ const fields = type.getFields(); | ||
export { ConnectionManager, CursorEncoder, KnexQueryBuilder as Knex, KnexMySQLFullTextQueryBuilder as KnexMySQL, QueryContext, QueryResult, gqlTypes, resolvers, typeDefs }; | ||
export { ConnectionManager, CursorEncoder, filter_transformers as FilterTransformers, KnexQueryBuilder as Knex, KnexMySQLFullTextQueryBuilder as KnexMySQL, QueryContext, QueryResult, gqlTypes, resolvers, typeDefs }; |
@@ -13,2 +13,3 @@ import { ORDER_DIRECTION } from './enums'; | ||
export declare type IInputFilter = IFilter | ICompoundFilter; | ||
export declare type FilterTransformer = (filter: IFilter) => IFilter; | ||
export interface ICursorObj<PublicAttributes> { | ||
@@ -65,3 +66,3 @@ orderDir: keyof typeof ORDER_DIRECTION; | ||
}; | ||
filterTransformer?: (filter: IFilter) => IFilter; | ||
filterTransformer?: FilterTransformer; | ||
useSuggestedValueLiteralTransforms?: boolean; | ||
@@ -73,3 +74,3 @@ } | ||
}; | ||
filterTransformer?: (filter: IFilter) => IFilter; | ||
filterTransformer?: FilterTransformer; | ||
useSuggestedValueLiteralTransforms?: boolean; | ||
@@ -76,0 +77,0 @@ searchColumns?: string[]; |
{ | ||
"name": "graphql-connections", | ||
"version": "9.0.0", | ||
"version": "9.1.0", | ||
"description": "Build and handle Relay-like GraphQL connections using a Knex query builder", | ||
@@ -60,3 +60,4 @@ "main": "dist/index.cjs.js", | ||
"knex": "0.20.13", | ||
"graphql": "14.7.0" | ||
"graphql": "14.7.0", | ||
"luxon": "2.0.1" | ||
}, | ||
@@ -69,2 +70,3 @@ "devDependencies": { | ||
"@types/supertest": "^2.0.7", | ||
"@types/luxon": "1.27.1", | ||
"apollo-server-koa": "^2.4.8", | ||
@@ -71,0 +73,0 @@ "dotenv": "^8.0.0", |
@@ -42,2 +42,5 @@ # GraphQL-Connections :diamond_shape_with_a_dot_inside: | ||
- [Filtering on computed columns](#filtering-on-computed-columns) | ||
- [Filter Transformation](#filter-transformation) | ||
- [Filter Transformers provided by this library](#filter-transformers-provided-by-this-library) | ||
- [FilterTransformers.castUnixSecondsFiltersToMysqlTimestamps](#filtertransformerscastunixsecondsfilterstomysqltimestamps) | ||
@@ -627,2 +630,4 @@ ## Install | ||
See the [filter transformation section for more details](#filter-transformation). | ||
##### filterMap | ||
@@ -828,1 +833,66 @@ | ||
``` | ||
## Filter Transformation | ||
Sometimes you may have a completely different data type in a filter from what is actually in your database. At Social Native, for example, our graph exposes all timestamps as Unix Seconds, but in our databases, the `timestamp` type is used. In order to easily manage filter value transformation from seconds to sql timestamps, we use the `filterTransformer` option. In the following example, we use the library-provided `FilterTransformers.castUnixSecondsFiltersToMysqlTimestamps` which takes a list of field names that should be transformed from unix seconds to mysql timestamps, if they are present and not falsy. | ||
```ts | ||
import {FilterTransformers} from 'graphql-connections'; | ||
type SomeGraphQLNode = { | ||
createdAt: string | number; | ||
updatedAt: string | number; | ||
}; | ||
const timestampFilterTransformer = FilterTransformers.castUnixSecondsFiltersToMysqlTimestamps< | ||
SomeGraphQLNode | ||
>(['createdAt', 'updatedAt']); | ||
const nodeConnection = new ConnectionManager<GqlActualDistribution | null>(input, inAttributeMap, { | ||
builderOptions: { | ||
filterTransformer: timestampFilterTransformer | ||
}, | ||
resultOptions: {nodeTransformer: sqlToGraphql.actualDistribution} | ||
}); | ||
``` | ||
A `compose` function is also exposed to combine multiple transformers together. The following example composes a transformer on 'createdAt', 'updatedAt' with one on 'startedAt', 'completedAt', creating one that will cast if any of the four were given. | ||
```ts | ||
import {FilterTransformers} from 'graphql-connections'; | ||
const timestampFilterTransformer = FilterTransformers.castUnixSecondsFiltersToMysqlTimestamps([ | ||
'createdAt', | ||
'updatedAt' | ||
]); | ||
const nodeConnection = new ConnectionManager<GqlActualDistribution | null>(input, inAttributeMap, { | ||
builderOptions: { | ||
filterTransformer: FilterTransformers.compose( | ||
timestampFilterTransformer, | ||
FilterTransformers.castUnixSecondsFiltersToMysqlTimestamps(['startedAt', 'completedAt']) | ||
) | ||
}, | ||
resultOptions: {nodeTransformer: sqlToGraphql.actualDistribution} | ||
}); | ||
``` | ||
### Filter Transformers provided by this library | ||
#### FilterTransformers.castUnixSecondsFiltersToMysqlTimestamps | ||
`castUnixSecondsFiltersToMysqlTimestamps` takes four arguments | ||
```ts | ||
function castUnixSecondsFiltersToMysqlTimestamps<T extends Record<string, unknown>>( | ||
filterFieldsToCast: Array<keyof T>, | ||
timezone: DateTimeOptions['zone'] = 'UTC', | ||
includeOffset = false, | ||
includeZone = false | ||
): FilterTransformer; | ||
``` | ||
`filterFieldsToCast` refers to the keys in a graphql node being filtered upon that will be transformed from unix seconds to MySQL timestamps. | ||
`timezone` is the expected timezone of the input seconds. **Default: UTC** | ||
`includeOffset` dictates whether the timestamp offset will be included in the generated timestamp **Default: false** | ||
`includeZone` dictates whether the timestamp's timezone will be included in the generated timestamp **Default: false** |
120090
20
2245
896
3
25
+ Addedluxon@2.0.1
+ Addedluxon@2.0.1(transitive)