Skip to content

Commit

Permalink
feat: add the ability to apply request specific base filters to the e…
Browse files Browse the repository at this point in the history
…lasticsearch request
  • Loading branch information
joemcelroy committed Jan 1, 2021
1 parent a118a53 commit e3aee9b
Show file tree
Hide file tree
Showing 19 changed files with 488 additions and 95 deletions.
26 changes: 26 additions & 0 deletions docs/docs/customisations-adding-base-filters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
id: customisations-add-base-filters
title: Adding base filters
sidebar_label: Adding base filters
slug: /customisations/add-base-filters
---

You want to apply search filters based on who or where the request is coming from. With `getBaseFilters`, you can return an array of filters to apply to the elasticsearch request.

The arguments are the same as the resolvers, where you can access the request context, parent object and args. for more information on resolvers, see [resolvers documentation](https://www.apollographql.com/docs/apollo-server/data/resolvers/)

In this example we show how you could apply a user's role to the search which comes from the user's JWT auth token. For more information on how to do JWT authentication in apollo, see [apollo authorization documentation](https://www.apollographql.com/docs/apollo-server/security/authentication/)

```javascript
const { typeDefs, withSearchkitResolvers, context } = SearchkitSchema({
config: searchkitConfig,
typeName: 'ResultSet',
hitTypeName: 'ResultHit',
getBaseFilters: (parent, parameters, ctx, info) => {
return [
{ term: { "account": parent.accountId }},
{ term: { "role": ctx.user.role }}
]
}
})
```
18 changes: 9 additions & 9 deletions docs/docs/guides-indexing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Either pick a cloud offering for example [qbox.io](www.qbox.io?ref=searchkit) or

Searchkit has a CLI which helps with figuring out your Elasticsearch schema and an example searchkit configuration to quickly get you started.

Copy the project from [indexer example]](https://github.com/searchkit/searchkit/tree/next/examples/indexer)
Copy the project from [indexer example](https://github.com/searchkit/searchkit/tree/next/examples/indexer)

Then within config.ts, add your own fields. Searchkit CLI will:
1. generate a Elasticsearch mapping file based on your configuration
Expand All @@ -22,21 +22,21 @@ Then within config.ts, add your own fields. Searchkit CLI will:

```javascript
withConfig({
index: 'imdb_movies', <--- the elasticsearch index name
host: "http://localhost:9200", <--- host url for elasticsearch
index: 'imdb_movies', <--- the elasticsearch index name
host: "http://localhost:9200", <--- host url for elasticsearch
source: movies, <---- Array of raw documents. Used with the field's sourceOptions. Optional
type: 'movie' <----- required for Elasticsearch v6. If you use elasticsearch 7, do *not* specify type.
fields: [
{
fieldName: 'type', <-- name of field. Must be lowercase
fields: [
{
fieldName: 'type', <-- name of field. Must be lowercase
stored: true, <-------- fields you want returned in the API.
facet: true, <-------- If you want the value to be used as a facet
searchable: true <----- If you want the field to be searchable within query
type: 'integer' <--- Optional. Default is keyword. Can be `integer`, `date` or `float`
sourceOptions: {
path: 'Type' <-- Used in indexing step. The key for the field value source.
sourceOptions: {
path: 'Type' <-- Used in indexing step. The key for the field value source.
transform: splitComma <-- Optional. To provide transformation from source to document field
}
}
}
]
})
Expand Down
7 changes: 4 additions & 3 deletions docs/docs/searchkit-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Key points:
| typeName | String. The root type name for searchkit. |
| hitTypeName | String. The hit type that will be used for all hits. Should match a type you have implemented. See ResultHit example above |
| addToQueryType | Boolean. Adds a `results` field to the root Query object which is handled the Searchkit resolver. Set this to false if you want to implement the searchkit root field yourself. See [Customising GraphQL field](https://www.searchkit.co/docs/customisations/changing-graphql-types) section for more information |
| getBaseFilters | Allows you to pass an array of elasticsearch queries to filter results by. See [Adding base filters documentation](https://www.searchkit.co//docs/customisations/add-base-filters) for more information.

### Customising the Searchkit Types
- typeName: Specifies the type name used for the Searchkit root query. Configured on SearchkitSchema options.
Expand Down Expand Up @@ -140,15 +141,15 @@ import {
const searchkitConfig = {
query: new CustomQuery({
queryFn: (query, qm) => {
return {
return [{
wildcard: {
field: {
value: query + '*',
boost: 1.0,
rewrite: 'constant_score'
}
}
}
}]
}
})
}
Expand All @@ -159,7 +160,7 @@ const searchkitConfig = {

| Option | Description |
| :------------- | :----------- |
| queryFn(query, queryManager) | Function. Query argument is the query string. queryManager argument is a class that keeps the query and filters that have been applied to search. For example you may want to adjust the query DSL based on what filters have been selected |
| queryFn(query, queryManager) | Function. Returns an array of filters. Query argument is the query string. queryManager argument is a class that keeps the query and filters that have been applied to search. For example you may want to adjust the query DSL based on what filters have been selected |

## Sorting
```javascript
Expand Down
8 changes: 6 additions & 2 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ module.exports = {
'searchkit-elastic-ui',
]
},
Examples: ['example-apps-next', 'example-apps-prisma', 'example-apps-aws-lambda', 'example-apps-create-react-app', 'example-apps-express'],
Examples: [
{ 'API + Frontend': ['example-apps-next'],
'API only': ['example-apps-prisma', 'example-apps-aws-lambda', 'example-apps-express' ],
'Frontend only': ['example-apps-create-react-app']
}],
Guides: [{ 'Guides': ['guides-elasticsearch-setup-indexing', 'guides-graphql-schema-cheat-sheet']}, {
'Upgrade Notes': ['v2-v3-migration', 'guides-upgrade-rc25']
}],
Customisations: {
'Graph QL': [ 'customisations-hit-resolver', 'customisations-graphql-multiple-configurations', 'customisations-graphql-types', 'customisations-ui-add-new-facet-class', ],
'GraphQL API': [ 'customisations-hit-resolver', 'customisations-graphql-multiple-configurations', 'customisations-graphql-types', 'customisations-ui-add-new-facet-class', 'customisations-add-base-filters' ],
'Components': ['customisations-ui-facet-display']
}
};
9 changes: 8 additions & 1 deletion examples/next/pages/api/graphql.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,14 @@ const searchkitConfig = {
}

const { typeDefs, withSearchkitResolvers, context } = SearchkitSchema({
config: searchkitConfig, typeName: 'ResultSet', hitTypeName: 'ResultHit', addToQueryType: true
config: searchkitConfig,
typeName: 'ResultSet',
hitTypeName: 'ResultHit',
addToQueryType: true,
getBaseFilters: (parent, parameters, ctx, info) => {
return [
]
}
})

export const config = {
Expand Down
19 changes: 15 additions & 4 deletions packages/searchkit-schema/src/core/SearchkitRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,30 @@ export default class SearchkitRequest {
private dataloader: any
private client: Client

constructor(private queryManager: QueryManager, private config: SearchkitConfig) {
constructor(
private queryManager: QueryManager,
private config: SearchkitConfig,
private baseFilters: Array<Record<string, unknown>>
) {
this.client = new Client({
node: this.config.host,
agent: () =>
new URL(this.config.host).protocol === 'http:' ? keepaliveAgent : keepaliveHttpsAgent
})

this.dataloader = new dataloader(async (partialQueries) => {
const query = {
bool: {
...(this.queryManager.hasQuery() && this.config.query
? { must: this.config.query.getFilter(this.queryManager) }
: {}),
filter: this.baseFilters
}
}

const baseQuery = {
size: 0,
...(this.queryManager.hasQuery() && this.config.query
? { query: this.config.query.getFilter(this.queryManager) }
: {}),
query,
post_filter: filterTransform(this.queryManager, this.config.facets)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/searchkit-schema/src/query/BaseQuery.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import QueryManager from '../core/QueryManager'

interface BaseQuery {
getFilter(queryManager: QueryManager): Record<string, unknown>
getFilter(queryManager: QueryManager): Array<Record<string, unknown>>
}

export default BaseQuery
2 changes: 1 addition & 1 deletion packages/searchkit-schema/src/query/CustomQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import QueryManager from '../core/QueryManager'
import BaseQuery from './BaseQuery'

interface CustomQueryConfig {
queryFn(query: string, queryManager?: QueryManager): Record<string, unknown>
queryFn(query: string, queryManager?: QueryManager): Array<Record<string, unknown>>
}

class CustomQuery implements BaseQuery {
Expand Down
14 changes: 8 additions & 6 deletions packages/searchkit-schema/src/query/MultiMatchQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ class MultiMatchQuery implements BaseQuery {

getFilter(queryManager: QueryManager) {
if (queryManager.hasQuery()) {
return {
multi_match: {
query: queryManager.getQuery(),
fields: this.config.fields
return [
{
multi_match: {
query: queryManager.getQuery(),
fields: this.config.fields
}
}
}
]
}
return {}
return []
}
}

Expand Down
33 changes: 18 additions & 15 deletions packages/searchkit-schema/src/query/__tests__/CustomQuery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,32 @@ describe('Custom Query', () => {
it('should allow custom ES query to be used to build query', () => {
const qm = new QueryManager([], 'test')
const cq = new CustomQuery({
queryFn: (query, qm) => ({
wildcard: {
field: {
value: query + '*',
boost: 1.0,
rewrite: 'constant_score'
queryFn: (query, qm) => [
{
wildcard: {
field: {
value: query + '*',
boost: 1.0,
rewrite: 'constant_score'
}
}
}
})
]
})

expect(cq.getFilter(qm)).toMatchInlineSnapshot(
{},
`
Object {
"wildcard": Object {
"field": Object {
"boost": 1,
"rewrite": "constant_score",
"value": "test*",
Array [
Object {
"wildcard": Object {
"field": Object {
"boost": 1,
"rewrite": "constant_score",
"value": "test*",
},
},
},
}
]
`
)
})
Expand Down
5 changes: 4 additions & 1 deletion packages/searchkit-schema/src/resolvers/ResultsResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ export default async (parent, parameters, ctx, info) => {
sortOptions: [],
...config
}
const baseFilters = ctx.searchkit.baseFilters[returnTypeName]
? ctx.searchkit.baseFilters[returnTypeName](parent, parameters, ctx, info)
: []
const queryManager = new QueryManager(parameters.filters, parameters.query)
const skRequest = new SearchkitRequest(queryManager, skConfig)
const skRequest = new SearchkitRequest(queryManager, skConfig, baseFilters)

return {
searchkit: {
Expand Down
6 changes: 6 additions & 0 deletions packages/searchkit-schema/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export interface SearchkitSchemaConfig {
hitTypeName: string
config: SearchkitConfig
addToQueryType?: boolean
getBaseFilters?: any
}

export default (schemaConfigs: SearchkitSchemaConfig | Array<SearchkitSchemaConfig>) => {
Expand Down Expand Up @@ -186,6 +187,10 @@ export default (schemaConfigs: SearchkitSchemaConfig | Array<SearchkitSchemaConf
...sum.context.searchkit.configs,
[typeName]: schemaConfig.config
},
baseFilters: {
...sum.context.searchkit.baseFilters,
[typeName]: schemaConfig.getBaseFilters
},
hitTypeMappings: {
...sum.context.searchkit.hitTypeMappings,
[typeName]: schemaConfig.hitTypeName
Expand All @@ -211,6 +216,7 @@ export default (schemaConfigs: SearchkitSchemaConfig | Array<SearchkitSchemaConf
context: {
searchkit: {
configs: {},
baseFilters: {},
hitTypeMappings: {}
}
}
Expand Down

0 comments on commit e3aee9b

Please sign in to comment.