added error handling for ngx-data-apollo
added handle wrapper
This commit is contained in:
parent
e5133b2f95
commit
ab99d5f076
@ -8,8 +8,10 @@
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"build-lib": "ng build @poweredsoft/ngx-data",
|
||||
"publish-lib": "npm publish dist/poweredsoft/ngx-data"
|
||||
"build-data": "ng build @poweredsoft/ngx-data",
|
||||
"build-apollo": "ng build @poweredsoft/ngx-data-apollo",
|
||||
"publish-data": "npm publish dist/poweredsoft/ngx-data",
|
||||
"publish-apollo": "npm publish dist/poweredsoft/ngx-data-apollo"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@poweredsoft/ngx-data-apollo",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.3",
|
||||
"peerDependencies": {
|
||||
"@poweredsoft/data": "^0.0.26",
|
||||
"@angular/common": "^8.2.4",
|
||||
|
@ -1,24 +1,32 @@
|
||||
import { IDataSourceOptions, IQueryCriteria, IDataSourceTransportOptions, IDataSourceQueryAdapterOptions, IDataSourceCommandAdapterOptions, IAdvanceQueryAdapter, IFilter, IAggregate, ISort, IGroup, ISimpleFilter, ICompositeFilter, IQueryExecutionGroupResult, IQueryExecutionResult, IAggregateResult, IGroupQueryResult } from '@poweredsoft/data';
|
||||
import { IDataSourceOptions, IQueryCriteria, IDataSourceTransportOptions, IDataSourceQueryAdapterOptions, IDataSourceCommandAdapterOptions, IAdvanceQueryAdapter, IFilter, IAggregate, ISort, IGroup, ISimpleFilter, ICompositeFilter, IQueryExecutionGroupResult, IQueryExecutionResult, IAggregateResult, IGroupQueryResult, IResolveCommandModelEvent, IDataSourceErrorMessage, IDataSourceValidationError } from '@poweredsoft/data';
|
||||
import { Apollo } from 'apollo-angular';
|
||||
import { IGraphQLAdvanceQueryResult, IGraphQLAdvanceQueryInput, IGraphQLAdvanceQueryFilterInput, IGraphQLAdvanceQueryAggregateInput, IGraphQLAdvanceQuerySortInput, IGraphQLAdvanceQueryGroupInput, FilterType, IGraphQLAdvanceQueryAggregateResult, IGraphQLVariantResult, AggregateType, IGraphQLAdvanceGroupResult } from './models';
|
||||
import gql from 'graphql-tag';
|
||||
import { DocumentNode } from 'graphql';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DocumentNode, GraphQLError } from 'graphql';
|
||||
import { map, catchError, switchMap } from 'rxjs/operators';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { FetchResult } from 'apollo-link';
|
||||
import { of } from 'zen-observable';
|
||||
import { ApolloError } from 'apollo-client';
|
||||
|
||||
export class GraphQLDataSourceOptionsBuilder<TModel, TKey> {
|
||||
|
||||
private _commands: { [key: string] : IDataSourceCommandAdapterOptions<any> };
|
||||
querySelect: string;
|
||||
private _commands: { [key: string] : IDataSourceCommandAdapterOptions<any> } = {};
|
||||
|
||||
constructor(private apollo: Apollo,
|
||||
private queryName: string,
|
||||
private queryInputName: string,
|
||||
private querySelect: string,
|
||||
querySelect: string | string[],
|
||||
private keyResolver: (model: TModel) => TKey,
|
||||
private defaultCriteria: IQueryCriteria,
|
||||
private manageNotificationMessage: boolean)
|
||||
{
|
||||
if (Array.isArray(querySelect))
|
||||
this.querySelect = querySelect.join(' ');
|
||||
else
|
||||
this.querySelect = querySelect;
|
||||
}
|
||||
|
||||
create(): IDataSourceOptions<TModel> {
|
||||
let ret: IDataSourceOptions<TModel> = {
|
||||
resolveIdField: this.keyResolver,
|
||||
@ -28,6 +36,7 @@ export class GraphQLDataSourceOptionsBuilder<TModel, TKey> {
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected createTransport(): IDataSourceTransportOptions<TModel> {
|
||||
let ret: IDataSourceTransportOptions<TModel> = {
|
||||
query: this.createQuery(),
|
||||
@ -122,6 +131,7 @@ export class GraphQLDataSourceOptionsBuilder<TModel, TKey> {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private createGraphQLQuery(query: IQueryCriteria): DocumentNode {
|
||||
return gql`
|
||||
query getAll($criteria: ${this.queryInputName}) {
|
||||
@ -163,14 +173,63 @@ export class GraphQLDataSourceOptionsBuilder<TModel, TKey> {
|
||||
groups: query.groups ? query.groups.map(this.convertGroup.bind(this)) : null
|
||||
};
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
public addMutation<TMutation, TMutationResult>(name: string, handle: (command: TMutation) => Observable<TMutationResult>) {
|
||||
|
||||
this._commands[name] = <IDataSourceCommandAdapterOptions<TMutation>> {
|
||||
/*public addMutationTest<TMutation, TMutationResult>(name: string, mutationName: string, mutationSelect?: string, resolveCommandModel?: (event: IResolveCommandModelEvent<TModel>) => Observable<TMutation & any>) {
|
||||
this._commands[name] = <IDataSourceCommandAdapterOptions<TModel>> {
|
||||
adapter: {
|
||||
handle: handle
|
||||
}
|
||||
handle: this.apollo.use()
|
||||
},
|
||||
resolveCommandModel: resolveCommandModel
|
||||
};
|
||||
|
||||
return this;
|
||||
}*/
|
||||
|
||||
public addMutation<TMutation, TMutationResult>(name: string, mutationName: string, handle: (command: TMutation) => Observable<FetchResult<TMutationResult>>, resolveCommandModel?: (event: IResolveCommandModelEvent<TModel>) => Observable<TMutation & any>) {
|
||||
const handleWrapper = command => {
|
||||
return handle(command)
|
||||
.pipe(
|
||||
map(result => {
|
||||
return result.data[mutationName];
|
||||
}),
|
||||
catchError((error: any) => {
|
||||
// should handle bad request with exception
|
||||
// should handle bad request with validation
|
||||
// should handle forbidden result 403
|
||||
// should handle not authorized result 401
|
||||
|
||||
const apolloError : ApolloError = error;
|
||||
if (!apolloError.networkError) {
|
||||
const validationError = apolloError.graphQLErrors.find(t => t.extensions.code == 'ValidationError');
|
||||
if (validationError) {
|
||||
const extensions = validationError.extensions;
|
||||
const result = Object.keys(extensions).filter(t => t != 'code').reduce((prev, attributeName) => {
|
||||
prev[attributeName] = extensions[attributeName];
|
||||
return prev;
|
||||
}, {});
|
||||
|
||||
return throwError(<IDataSourceValidationError>{
|
||||
type: 'validation',
|
||||
errors: result
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return throwError(<IDataSourceErrorMessage>{
|
||||
type: 'message',
|
||||
message: apolloError.message
|
||||
});
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
this._commands[name] = <IDataSourceCommandAdapterOptions<TModel>> {
|
||||
adapter: {
|
||||
handle: handleWrapper
|
||||
},
|
||||
resolveCommandModel: resolveCommandModel
|
||||
};
|
||||
|
||||
return this;
|
||||
|
@ -9,3 +9,7 @@
|
||||
<button (click)="testGraphQL()">
|
||||
Test GraphQL query
|
||||
</button>
|
||||
|
||||
<button (click)="testGraphQLMutation()">
|
||||
Test GraphQL mutation
|
||||
</button>
|
@ -1,8 +1,12 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { GenericRestDataSourceService } from 'projects/poweredsoft/ngx-data/src/public-api';
|
||||
import { of } from 'rxjs';
|
||||
import { DataSource } from '@poweredsoft/data';
|
||||
import { of, Observable } from 'rxjs';
|
||||
import { DataSource, IResolveCommandModelEvent } from '@poweredsoft/data';
|
||||
import { GraphQLDataSourceService } from 'projects/poweredsoft/ngx-data-apollo/src/public-api';
|
||||
import { Apollo } from 'apollo-angular';
|
||||
import gql from 'graphql-tag';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { DocumentNode } from 'graphql';
|
||||
|
||||
|
||||
export interface IContact {
|
||||
@ -17,6 +21,11 @@ export interface ICustomerModel {
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface IFooCommand {
|
||||
amount: number;
|
||||
comment: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
@ -26,7 +35,7 @@ export class AppComponent implements OnInit {
|
||||
title = 'ngx-data';
|
||||
dataSource: DataSource<ICustomerModel>;
|
||||
|
||||
constructor(genericService: GenericRestDataSourceService, private graphQLService: GraphQLDataSourceService) {
|
||||
constructor(genericService: GenericRestDataSourceService, private apollo: Apollo, private graphQLService: GraphQLDataSourceService) {
|
||||
const keyResolver = (model: ICustomerModel) => model.id;
|
||||
|
||||
const transportOptions = genericService.createStandardRestTransportOptions('api/customer', keyResolver);
|
||||
@ -77,6 +86,70 @@ export class AppComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
testGraphQLMutation() {
|
||||
const builder = this.graphQLService.createDataSourceOptionsBuilder<IContact, number>(
|
||||
'contacts',
|
||||
'GraphQLAdvanceQueryOfContactModelInput',
|
||||
'id firstName lastName',
|
||||
(m) => m.id,
|
||||
{
|
||||
groups: [
|
||||
{
|
||||
path: 'sex'
|
||||
}
|
||||
],
|
||||
aggregates: [
|
||||
{
|
||||
path: 'id',
|
||||
type: 'Max'
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
builder.addMutation<IFooCommand, string>('create', 'foo', (command) => {
|
||||
return this.apollo.mutate<string>({
|
||||
mutation: gql`mutation executeFoo($command: FooCommandInput) {
|
||||
foo(params: $command)
|
||||
}`,
|
||||
variables: {
|
||||
command: command
|
||||
}
|
||||
});
|
||||
},
|
||||
(event) => {
|
||||
console.log(event);
|
||||
if (event.model.id)
|
||||
|
||||
return of({
|
||||
firstName: 'hello world'
|
||||
});
|
||||
});
|
||||
|
||||
const dataSourceOptions = builder.create();
|
||||
const dataSource = new DataSource<IContact>(dataSourceOptions);
|
||||
let event: IResolveCommandModelEvent<IContact> = {
|
||||
command: 'create',
|
||||
model: {
|
||||
id: 1,
|
||||
firstName: 'hello',
|
||||
lastName: 'world'
|
||||
}
|
||||
};
|
||||
|
||||
dataSource.resolveCommandModelByName(event)
|
||||
.subscribe((result) => {
|
||||
console.log('resolve result', result);
|
||||
});
|
||||
|
||||
dataSource.executeCommandByName('create', {
|
||||
amount: 0,
|
||||
//comment: "hello"
|
||||
}).subscribe((result) => {
|
||||
console.log(result);
|
||||
})
|
||||
}
|
||||
|
||||
testGraphQL() {
|
||||
const builder = this.graphQLService.createDataSourceOptionsBuilder<IContact, number>(
|
||||
'contacts',
|
||||
|
@ -3,7 +3,7 @@ import {ApolloModule, APOLLO_OPTIONS} from 'apollo-angular';
|
||||
import {HttpLinkModule, HttpLink} from 'apollo-angular-link-http';
|
||||
import {InMemoryCache} from 'apollo-cache-inmemory';
|
||||
|
||||
const uri = 'https://localhost:5001/graphql'; // <-- add the URL of the GraphQL server here
|
||||
const uri = 'http://localhost:5000/graphql'; // <-- add the URL of the GraphQL server here
|
||||
export function createApollo(httpLink: HttpLink) {
|
||||
return {
|
||||
link: httpLink.create({uri}),
|
||||
|
Loading…
Reference in New Issue
Block a user