-
Notifications
You must be signed in to change notification settings - Fork 25
Feat/fed search cleanup #920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ciaranschutte
merged 10 commits into
feature/federated_search
from
feat/fed_search_cleanup
Mar 15, 2025
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
c3d1c25
add placeholder
9d6fe98
Adjust config template example and file
f1e4666
remove unused arranger constructor param
d36c021
reorder constants file, parse env var
4d00dde
update arranger network config type
0d22b37
type, add gql server types
b00e5b2
graphqlRoutes, remove unused import, export func
2268f85
resolver creation, improve TS usage, split functionality into distinc…
77d4e59
add surrounding brackets for func
2eb1e5c
cleanup schema resolvers
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -21,6 +21,8 @@ npm run prepare | |
|
|
||
| ## Federated Search | ||
|
|
||
| [Placeholder] | ||
|
|
||
| ### Config | ||
|
|
||
| [Placeholder] | ||
| [Placeholder] | ||
This file contains hidden or 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 hidden or 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 |
|---|---|---|
| @@ -1,11 +1,5 @@ | ||
| { | ||
| "network": { | ||
| "servers": [ | ||
| { | ||
| "displayName": "Toronto", | ||
| "graphqlUrl": "http://.../graphql", | ||
| "documentType": "file" | ||
| } | ||
| ] | ||
| "servers": [] | ||
| } | ||
| } |
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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,24 @@ | ||
| import { Client } from '@elastic/elasticsearch'; | ||
| import { GraphQLResolveInfo } from 'graphql'; | ||
|
|
||
| export type Context = { | ||
| esClient: Client; | ||
| }; | ||
|
|
||
| export type ResolverOutput<T> = T | Promise<T>; | ||
|
|
||
| /** | ||
| * GQL resolver | ||
| * | ||
| * @param root - Parent object of a query. | ||
| * @param args - Query arguments. | ||
| * @param context - Context passed to apollo-server for queries. | ||
| * @param info - GraphQL info object. | ||
| * @return Returns resolved value; | ||
| */ | ||
| export type Resolver<Root = {}, QueryArgs = Object, ReturnValue = undefined> = ( | ||
| root: Root, | ||
| args: QueryArgs, | ||
| context: Context, | ||
| info: GraphQLResolveInfo, | ||
| ) => ResolverOutput<ReturnValue> | ResolverOutput<ReturnValue>; | ||
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ import expressPlayground from 'graphql-playground-middleware-express'; | |
|
|
||
| import { mergeSchemas } from '@graphql-tools/schema'; | ||
| import getConfigObject, { initializeSets } from './config'; | ||
| import { DEBUG_MODE, ENABLE_NETWORK_AGGREGATION, ES_PASS, ES_USER } from './config/constants'; | ||
| import { DEBUG_MODE, ES_PASS, ES_USER } from './config/constants'; | ||
| import { ConfigProperties } from './config/types'; | ||
| import { addMappingsToTypes, extendFields, fetchMapping } from './mapping'; | ||
| import { extendColumns, extendFacets, flattenMappingToFields } from './mapping/extendMapping'; | ||
|
|
@@ -243,7 +243,7 @@ const createEndpoint = async ({ esClient, graphqlOptions = {}, mockSchema, schem | |
| return router; | ||
| }; | ||
|
|
||
| const createSchemasFromConfigs = async ({ | ||
| export const createSchemasFromConfigs = async ({ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🙏 I knew we'd need this export at some point, just couldn't remember which was the one function needed after a few months |
||
| configsSource = '', | ||
| enableAdmin, | ||
| enableDocumentHits, | ||
|
|
@@ -272,7 +272,7 @@ const createSchemasFromConfigs = async ({ | |
|
|
||
| const schemasToMerge = [schema]; | ||
|
|
||
| /* | ||
| /** | ||
| * Federated Network Search | ||
| */ | ||
| if (enableNetworkAggregation) { | ||
|
|
||
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 |
|---|---|---|
|
|
@@ -2,12 +2,48 @@ import getFields from 'graphql-fields'; | |
|
|
||
| import { buildAggregations, buildQuery, flattenAggregations } from '../middleware'; | ||
|
|
||
| import { Resolver } from '@/gqlServer'; | ||
| import { GetServerSideFilterFn } from '@/utils/getDefaultServerSideFilter'; | ||
| import { resolveSetsInSqon } from './hackyTemporaryEsSetResolution'; | ||
| import { Relation } from './masking'; | ||
| import { AggregationQuery, Root } from './types'; | ||
| import compileFilter from './utils/compileFilter'; | ||
| import esSearch from './utils/esSearch'; | ||
|
|
||
| export default ({ type, getServerSideFilter }) => { | ||
| return async ( | ||
| const toGraphqlField = (acc: Aggregations, [a, b]: [string, Aggregation]) => ({ | ||
| ...acc, | ||
| [a.replace(/\./g, '__')]: b, | ||
| }); | ||
| export const aggregationsToGraphql = (aggregations: Aggregations) => { | ||
| return Object.entries(aggregations).reduce<Aggregations>(toGraphqlField, {}); | ||
| }; | ||
|
|
||
| /* | ||
| * Types | ||
| */ | ||
| export type Bucket = { | ||
| doc_count: number; | ||
| key: string; | ||
| relation: Relation; | ||
| }; | ||
|
|
||
| export type Aggregation = { | ||
| bucket_count: number; | ||
| buckets: Bucket[]; | ||
| }; | ||
|
|
||
| export type Aggregations = Record<string, Aggregation>; | ||
|
|
||
| export type AggregationsResolver = Resolver<Root, AggregationQuery, Promise<Aggregations>>; | ||
|
|
||
| const getAggregationsResolver = ({ | ||
| type, | ||
| getServerSideFilter, | ||
| }: { | ||
| type: Record<string, any>; | ||
| getServerSideFilter: GetServerSideFilterFn | undefined; | ||
| }) => { | ||
| const resolver: Resolver<unknown, AggregationQuery, Promise<Aggregations>> = async ( | ||
| obj, | ||
| { filters, aggregations_filter_themselves, include_missing = true }, | ||
| context, | ||
|
|
@@ -26,7 +62,7 @@ export default ({ type, getServerSideFilter }) => { | |
| nestedFieldNames, | ||
| filters: compileFilter({ | ||
| clientSideFilter: resolvedFilter, | ||
| serverSideFilter: getServerSideFilter(context), | ||
| serverSideFilter: getServerSideFilter && getServerSideFilter(), | ||
| }), | ||
| }); | ||
|
|
||
|
|
@@ -48,6 +84,7 @@ export default ({ type, getServerSideFilter }) => { | |
| const response = await esSearch(esClient)({ | ||
| index: type.index, | ||
| size: 0, | ||
| // @ts-expect-error - valid search query parameter in ES 7.17, not in types | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmmm! |
||
| _source: false, | ||
| body, | ||
| }); | ||
|
|
@@ -58,9 +95,8 @@ export default ({ type, getServerSideFilter }) => { | |
|
|
||
| return aggregations; | ||
| }; | ||
| }; | ||
|
|
||
| const toGraphqlField = (acc, [a, b]) => ({ ...acc, [a.replace(/\./g, '__')]: b }); | ||
| export const aggregationsToGraphql = (aggregations) => { | ||
| return Object.entries(aggregations).reduce(toGraphqlField, {}); | ||
| return resolver; | ||
| }; | ||
|
|
||
| export default getAggregationsResolver; | ||
This file contains hidden or 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,51 @@ | ||
| import { Resolver } from '@/gqlServer'; | ||
| import { get } from 'lodash'; | ||
| import { applyAggregationMasking } from './masking'; | ||
| import { AggregationsResolver } from './resolveAggregations'; | ||
| import { HitsQuery, Root } from './types'; | ||
|
|
||
| type HitsResolver = Resolver<Root, HitsQuery, Promise<{ total: number }>>; | ||
|
|
||
| /** | ||
| * Resolver for "aggregation only mode" of Arranger where "hits" is based on "aggregations" | ||
| * Calculate hits from aggregation data, instead of using "hits" ES response field | ||
| * | ||
| * If "aggregations" field is not in query, return 0 | ||
| * | ||
| * @param aggregationsResolver - resolver ES query code for aggregations | ||
| * @returns Returns a total count that is less than or equal to the actual total hits in the query. | ||
| */ | ||
| export const getHitsFromAggsResolver = (aggregationsResolver: AggregationsResolver) => { | ||
| const resolver: HitsResolver = async (obj, args, context, info) => { | ||
| /* | ||
| * Get "aggregations" field from full query if found | ||
| * Popular gql parsing libs parse the "info" property which may not include full query based on schema | ||
| */ | ||
| const aggregationsPath = 'operation.selectionSet.selections[0].selectionSet.selections'; | ||
| const aggregationsSelectionSet = get(info, aggregationsPath, []).find( | ||
| (selection: { kind: string; name: { value: string } }) => | ||
| selection.kind === 'Field' && selection.name.value === 'aggregations', | ||
| ); | ||
|
|
||
| if (aggregationsSelectionSet) { | ||
| const modifiedInfo = { ...info, fieldNodes: [aggregationsSelectionSet] }; | ||
|
|
||
| const aggregations = await aggregationsResolver( | ||
| obj, | ||
| // @ts-ignore | ||
| // modifying the query info field inline so it can query aggregations correctly | ||
| // not idiomatic so doesn't line up with typings from graphql | ||
| info.variableValues, | ||
| context, | ||
| modifiedInfo, | ||
| ); | ||
| const { hitsTotal: total } = applyAggregationMasking({ | ||
| aggregations, | ||
| }); | ||
| return { total }; | ||
| } else { | ||
| return { total: 0 }; | ||
| } | ||
| }; | ||
| return resolver; | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: we will need to abstract this into an ESClient provider, so users can switch seamlessly between ES v7 and v8