-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(angular-data-source-graphql): added graphql data source
- Loading branch information
Showing
16 changed files
with
1,293 additions
and
81 deletions.
There are no files selected for viewing
1,008 changes: 1,008 additions & 0 deletions
1,008
projects/neuroglia/angular-data-source-graphql/src/lib/graphql-data-source.spec.ts
Large diffs are not rendered by default.
Oops, something went wrong.
108 changes: 108 additions & 0 deletions
108
projects/neuroglia/angular-data-source-graphql/src/lib/graphql-data-source.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,108 @@ | ||
import { Observable } from 'rxjs'; | ||
import buildQuery from 'odata-query'; | ||
import { HttpRequestInfo, ODataQueryResultDto, logHttpRequest } from '@neuroglia/angular-rest-core'; | ||
import { CombinedParams, QueryableDataSource } from '@neuroglia/angular-data-source-queryable'; | ||
import { Injectable, inject } from '@angular/core'; | ||
import { | ||
GRAPHQL_DATA_SOURCE_ARGS, | ||
GRAPHQL_DATA_SOURCE_ENDPOINT, | ||
GRAPHQL_DATA_SOURCE_FIELDS, | ||
GRAPHQL_DATA_SOURCE_QUERY_BUILDER, | ||
GRAPHQL_DATA_SOURCE_TARGET, | ||
GRAPHQL_DATA_SOURCE_VARIABLES_MAPPER, | ||
} from './injection-tokens'; | ||
import { GraphQLQueryArguments, GraphQLQueryBuilder, GraphQLVariablesMapper } from './models'; | ||
|
||
/** | ||
* A data source used to handle GraphQL interactions | ||
*/ | ||
@Injectable() | ||
export class GraphQLDataSource<T = any> extends QueryableDataSource<T> { | ||
protected endpoint: string = inject(GRAPHQL_DATA_SOURCE_ENDPOINT); | ||
protected target: string = inject(GRAPHQL_DATA_SOURCE_TARGET); | ||
protected fields: string[] = inject(GRAPHQL_DATA_SOURCE_FIELDS); | ||
protected args: GraphQLQueryArguments | null = inject(GRAPHQL_DATA_SOURCE_ARGS, { optional: true }); | ||
protected variablesMapper: GraphQLVariablesMapper | null = inject(GRAPHQL_DATA_SOURCE_VARIABLES_MAPPER, { | ||
optional: true, | ||
}); | ||
protected queryBuilder: GraphQLQueryBuilder | null = inject(GRAPHQL_DATA_SOURCE_QUERY_BUILDER, { optional: true }); | ||
|
||
constructor() { | ||
super(); | ||
this.loggerName = `GraphQLDataSource|${this.endpoint}`; | ||
this.logger = this.namedLoggingServiceFactory.create(this.loggerName); | ||
} | ||
|
||
/** | ||
* Builds the query | ||
* @param combinedParams | ||
*/ | ||
protected buildQuery(combinedParams: CombinedParams<T>): string { | ||
if (this.queryBuilder) { | ||
return this.queryBuilder(this.target, this.args, this.fields, combinedParams); | ||
} | ||
const operationName = 'QueryDataSource'; | ||
const select = combinedParams[0]?.select; | ||
const expand = combinedParams[1]?.expand; | ||
let selectAndExpand: string[] = []; | ||
if (select) { | ||
if (!Array.isArray(select)) { | ||
selectAndExpand.push(select as string); | ||
} else if (select.length) { | ||
selectAndExpand = [...selectAndExpand, ...(select as string[])]; | ||
} | ||
} | ||
if (expand) { | ||
if (!Array.isArray(expand)) { | ||
selectAndExpand.push(expand as string); | ||
} else if (expand.length) { | ||
selectAndExpand = [...selectAndExpand, ...(expand as string[])]; | ||
} | ||
} | ||
const fields = (!selectAndExpand.length ? this.fields : selectAndExpand).join('\n'); | ||
let operationArgs = '($options: QueryOptionsInput)'; | ||
let targetArgs = '(options: $options)'; | ||
if (this.args && Object.keys(this.args).length) { | ||
operationArgs = `(${Object.entries(this.args).reduce( | ||
(acc, [name, type], idx) => acc + `${idx !== 0 ? ',' : ''}$${name}: ${type}`, | ||
'', | ||
)})`; | ||
targetArgs = `(${Object.keys(this.args).reduce( | ||
(acc, name, idx) => acc + `${idx !== 0 ? ',' : ''}${name}: $${name}`, | ||
'', | ||
)})`; | ||
} | ||
const query = `query ${operationName} ${operationArgs} { | ||
${this.target} ${targetArgs} { | ||
${fields} | ||
} | ||
}`; | ||
const options = Object.fromEntries( | ||
combinedParams | ||
.flatMap((param) => (param ? Object.entries(param) : [])) | ||
.filter(([key, value]) => key != 'select' && (!Array.isArray(value) ? value != null : !!value?.length)), | ||
); | ||
const variables = this.variablesMapper ? this.variablesMapper(this.args, combinedParams) : { options }; | ||
return JSON.stringify({ operationName, query, variables }); | ||
} | ||
|
||
/** | ||
* Queries the GraphQL endpoint | ||
* @param query | ||
*/ | ||
protected gatherData(query: string): Observable<ODataQueryResultDto<T>> { | ||
const url: string = `${this.endpoint}`; | ||
const httpRequestInfo: HttpRequestInfo = new HttpRequestInfo({ | ||
clientServiceName: this.loggerName, | ||
methodName: 'gatherData', | ||
verb: 'post', | ||
url, | ||
}); | ||
return logHttpRequest( | ||
this.logger, | ||
this.errorObserver, | ||
this.http.post<ODataQueryResultDto<T>>(url, JSON.parse(query)), | ||
httpRequestInfo, | ||
); | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
projects/neuroglia/angular-data-source-graphql/src/lib/injection-tokens.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,13 @@ | ||
import { InjectionToken } from '@angular/core'; | ||
import { GraphQLQueryBuilder, GraphQLVariablesMapper } from './models'; | ||
|
||
export const GRAPHQL_DATA_SOURCE_ENDPOINT = new InjectionToken<string>('graphql-data-source-endpoint'); | ||
export const GRAPHQL_DATA_SOURCE_TARGET = new InjectionToken<string>('graphql-data-source-target'); | ||
export const GRAPHQL_DATA_SOURCE_FIELDS = new InjectionToken<string[]>('graphql-data-source-fields'); | ||
export const GRAPHQL_DATA_SOURCE_ARGS = new InjectionToken<{ [arg: string]: string }>('graphql-data-source-args'); | ||
export const GRAPHQL_DATA_SOURCE_QUERY_BUILDER = new InjectionToken<GraphQLQueryBuilder>( | ||
'graphql-data-source-query-builder', | ||
); | ||
export const GRAPHQL_DATA_SOURCE_VARIABLES_MAPPER = new InjectionToken<GraphQLVariablesMapper>( | ||
'graphql-data-source-variables-mapper', | ||
); |
6 changes: 6 additions & 0 deletions
6
projects/neuroglia/angular-data-source-graphql/src/lib/models/graphql-query-arguments.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,6 @@ | ||
/** | ||
* An { argumentName: argumentType } map | ||
*/ | ||
export interface GraphQLQueryArguments { | ||
[key: string]: string; | ||
} |
12 changes: 12 additions & 0 deletions
12
projects/neuroglia/angular-data-source-graphql/src/lib/models/graphql-query-builder.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,12 @@ | ||
import { CombinedParams } from '@neuroglia/angular-data-source-queryable'; | ||
import { GraphQLQueryArguments } from './graphql-query-arguments'; | ||
|
||
/** | ||
* Builds a GraphQL query based on the provided context | ||
*/ | ||
export type GraphQLQueryBuilder = <T = any>( | ||
target: string, | ||
args: GraphQLQueryArguments | null, | ||
fields: string[], | ||
combinedParams: CombinedParams<T>, | ||
) => string; |
10 changes: 10 additions & 0 deletions
10
projects/neuroglia/angular-data-source-graphql/src/lib/models/graphql-variables-mapper.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,10 @@ | ||
import { CombinedParams } from '@neuroglia/angular-data-source-queryable'; | ||
import { GraphQLQueryArguments } from './graphql-query-arguments'; | ||
|
||
/** | ||
* Builds a GraphQL query based on the provided context | ||
*/ | ||
export type GraphQLVariablesMapper = <T = any>( | ||
args: GraphQLQueryArguments | null, | ||
combinedParams: CombinedParams<T>, | ||
) => any; |
3 changes: 3 additions & 0 deletions
3
projects/neuroglia/angular-data-source-graphql/src/lib/models/index.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,3 @@ | ||
export * from './graphql-query-builder'; | ||
export * from './graphql-query-arguments'; | ||
export * from './graphql-variables-mapper'; |
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
Oops, something went wrong.