From 2485bdb83503189c48eda50c1f15369592498f73 Mon Sep 17 00:00:00 2001 From: David Lebee Date: Wed, 18 Aug 2021 00:22:47 -0400 Subject: [PATCH] single object data source. --- .../lib/BaseHttpDataSourceOptionsBuilder.ts | 128 +++++++++++++++++ .../ngx-data/src/lib/HttpDataSourceBuilder.ts | 130 ++---------------- .../src/lib/SingleObjectDataSourceBuilder.ts | 103 ++++++++++++++ 3 files changed, 241 insertions(+), 120 deletions(-) create mode 100644 projects/poweredsoft/ngx-data/src/lib/BaseHttpDataSourceOptionsBuilder.ts create mode 100644 projects/poweredsoft/ngx-data/src/lib/SingleObjectDataSourceBuilder.ts diff --git a/projects/poweredsoft/ngx-data/src/lib/BaseHttpDataSourceOptionsBuilder.ts b/projects/poweredsoft/ngx-data/src/lib/BaseHttpDataSourceOptionsBuilder.ts new file mode 100644 index 0000000..e728319 --- /dev/null +++ b/projects/poweredsoft/ngx-data/src/lib/BaseHttpDataSourceOptionsBuilder.ts @@ -0,0 +1,128 @@ +import { HttpClient, HttpErrorResponse } from "@angular/common/http"; +import { DataSource, IDataSource, IDataSourceCommandAdapterOptions, IDataSourceError, IDataSourceErrorMessage, IDataSourceOptions, IDataSourceQueryAdapterOptions, IDataSourceTransportOptions, IDataSourceValidationError, IQueryCriteria, IResolveCommandModelEvent } from "@poweredsoft/data"; +import { Observable, of, throwError } from "rxjs"; +import { catchError, switchMap } from "rxjs/operators"; + + + +export abstract class BaseHttpDataSourceOptionsBuilder { + protected _commands: { [key: string]: IDataSourceCommandAdapterOptions; } = {}; + protected _keyResolver: (model: TModel) => TKey; + protected _defaultCriteria: IQueryCriteria; + protected _query: IDataSourceQueryAdapterOptions; + + constructor(protected http: HttpClient) { + } + + createDataSource(): IDataSource { + return new DataSource(this.createOptions()); + } + + protected createTransport(): IDataSourceTransportOptions { + let ret: IDataSourceTransportOptions = { + query: this._query, + commands: this._commands + }; + return ret; + } + + public keyResolver(resolver: (model: TModel) => TKey) { + this._keyResolver = resolver; + return this; + } + + + createOptions(): IDataSourceOptions { + let ret: IDataSourceOptions = { + resolveIdField: this._keyResolver, + defaultCriteria: this._defaultCriteria, + transport: this.createTransport() + }; + return ret; + } + + private _messageErrorHandler(err: HttpErrorResponse) { + + if (typeof err.error == "object") { + // if status not okay then its an exception error + if (err.error.hasOwnProperty('Message') && typeof (err.error['Message']) == "string") { + return throwError({ + type: 'message', + message: err.error['Message'] + }); + } + else if (err.error.hasOwnProperty('message') && typeof (err.error['message']) == "string") { + return throwError({ + type: 'message', + message: err.error['message'] + }); + } + } + + // general error message + if (typeof (err.error) == "string") { + return throwError({ + type: 'message', + message: err.error + }); + } + + return throwError({ + type: 'message', + message: 'UNEXPECTED_ERROR_MESSAGE' + }); + } + + private _handleErrorPipe(err: HttpErrorResponse): Observable { + + if (err.status == 400) { + if (err.error && err.error.errors) + return throwError({ + type: 'validation', + errors: err.error.errors + }); + } + + return this._messageErrorHandler(err); + } + + + + + public addCommandByCallback(name: string, commandHandler: (command: TCommand) => Observable, resolveCommandModel?: (event: IResolveCommandModelEvent) => Observable) { + const handleWrapper = command => { + return commandHandler(command).pipe(catchError(err => this._handleErrorPipe.bind(this))); + }; + + this._commands[name] = >{ + adapter: { + handle: handleWrapper + }, + resolveCommandModel: resolveCommandModel + }; + + return this; + } + + public addCommandByUrl(name: string, url: string, resolveCommandModel?: (event: IResolveCommandModelEvent) => Observable, beforeCommand?: (command: TCommand) => Observable) { + const handleWrapper = command => { + const finalBeforeCommand = beforeCommand || (_ => of(command)); + return finalBeforeCommand(command) + .pipe( + switchMap(finalCommand => { + return this.http.post(url, finalCommand).pipe(catchError(this._handleErrorPipe.bind(this))); + }) + ); + }; + + this._commands[name] = >{ + adapter: { + handle: handleWrapper + }, + resolveCommandModel: resolveCommandModel + }; + + return this; + } + +} diff --git a/projects/poweredsoft/ngx-data/src/lib/HttpDataSourceBuilder.ts b/projects/poweredsoft/ngx-data/src/lib/HttpDataSourceBuilder.ts index 751a47f..69a6dc4 100644 --- a/projects/poweredsoft/ngx-data/src/lib/HttpDataSourceBuilder.ts +++ b/projects/poweredsoft/ngx-data/src/lib/HttpDataSourceBuilder.ts @@ -1,46 +1,17 @@ -import { HttpClient, HttpErrorResponse, HttpResponse } from "@angular/common/http"; -import { DataSource, IDataSource, IDataSourceCommandAdapterOptions, IDataSourceError, IDataSourceErrorMessage, IDataSourceOptions, IDataSourceQueryAdapterOptions, IDataSourceTransportOptions, IDataSourceValidationError, IQueryCriteria, IQueryExecutionGroupResult, IQueryExecutionResult, IResolveCommandModelEvent } from "@poweredsoft/data"; -import { Observable, of, throwError } from "rxjs"; -import { catchError, switchMap } from "rxjs/operators"; +import { HttpClient, HttpResponse } from "@angular/common/http"; +import { IQueryCriteria, IQueryExecutionGroupResult, IQueryExecutionResult } from "@poweredsoft/data"; +import { Observable, of } from "rxjs"; +import { switchMap } from "rxjs/operators"; +import { BaseHttpDataSourceOptionsBuilder } from "./BaseHttpDataSourceOptionsBuilder"; - - -export class HttpDataSourceOptionsBuilder { - - private _commands: { [key: string]: IDataSourceCommandAdapterOptions } = {}; +export class HttpDataSourceOptionsBuilder + extends BaseHttpDataSourceOptionsBuilder +{ private _beforeRead: (TQuery: IQueryCriteria) => Observable; - private _keyResolver: (model: TModel) => TKey; - private _defaultCriteria: IQueryCriteria; - private _query: IDataSourceQueryAdapterOptions; - constructor(private http: HttpClient) { - } - - createOptions(): IDataSourceOptions { - let ret: IDataSourceOptions = { - resolveIdField: this._keyResolver, - defaultCriteria: this._defaultCriteria, - transport: this.createTransport() - }; - return ret; - } - - createDataSource(): IDataSource { - return new DataSource(this.createOptions()); - } - - protected createTransport(): IDataSourceTransportOptions { - let ret: IDataSourceTransportOptions = { - query: this._query, - commands: this._commands - }; - return ret; - } - - public keyResolver(resolver: (model: TModel) => TKey) { - this._keyResolver = resolver; - return this; + constructor(http: HttpClient) { + super(http); } public beforeRead(beforeRead: (query: TDynamicQuery) => Observable) { @@ -84,87 +55,6 @@ export class HttpDataSourceOptionsBuilder { return this; } - private _messageErrorHandler(err: HttpErrorResponse) { - - if (typeof err.error == "object") { - // if status not okay then its an exception error - if (err.error.hasOwnProperty('Message') && typeof (err.error['Message']) == "string") { - return throwError({ - type: 'message', - message: err.error['Message'] - }); - } - else if (err.error.hasOwnProperty('message') && typeof (err.error['message']) == "string") { - return throwError({ - type: 'message', - message: err.error['message'] - }); - } - } - - // general error message - if (typeof (err.error) == "string") { - return throwError({ - type: 'message', - message: err.error - }); - } - - return throwError({ - type: 'message', - message: 'UNEXPECTED_ERROR_MESSAGE' - }); - } - - private _handleErrorPipe(err: HttpErrorResponse): Observable { - - if (err.status == 400) { - if (err.error && err.error.errors) - return throwError({ - type: 'validation', - errors: err.error.errors - }); - } - - return this._messageErrorHandler(err); - } - - public addCommandByCallback(name: string, commandHandler: (command: TCommand) => Observable, resolveCommandModel?: (event: IResolveCommandModelEvent) => Observable) { - const handleWrapper = command => { - return commandHandler(command).pipe(catchError(err => this._handleErrorPipe.bind(this))); - }; - - this._commands[name] = >{ - adapter: { - handle: handleWrapper - }, - resolveCommandModel: resolveCommandModel - }; - - return this; - } - - public addCommandByUrl(name: string, url: string, resolveCommandModel?: (event: IResolveCommandModelEvent) => Observable, beforeCommand?: (command: TCommand) => Observable) { - const handleWrapper = command => { - const finalBeforeCommand = beforeCommand || (_ => of(command)); - return finalBeforeCommand(command) - .pipe( - switchMap(finalCommand => { - return this.http.post(url, finalCommand).pipe(catchError(this._handleErrorPipe.bind(this))); - }) - ); - }; - - this._commands[name] = >{ - adapter: { - handle: handleWrapper - }, - resolveCommandModel: resolveCommandModel - }; - - return this; - } - defaultCriteria(criteria: IQueryCriteria) { this._defaultCriteria = criteria; return this; diff --git a/projects/poweredsoft/ngx-data/src/lib/SingleObjectDataSourceBuilder.ts b/projects/poweredsoft/ngx-data/src/lib/SingleObjectDataSourceBuilder.ts new file mode 100644 index 0000000..a7bbfef --- /dev/null +++ b/projects/poweredsoft/ngx-data/src/lib/SingleObjectDataSourceBuilder.ts @@ -0,0 +1,103 @@ +import { HttpClient, HttpResponse } from "@angular/common/http"; +import { Query } from "@angular/core"; +import { IQueryCriteria, IQueryExecutionGroupResult, IQueryExecutionResult, IQueryExecutionResultPaging } from "@poweredsoft/data"; +import { Observable, of } from "rxjs"; +import { map, switchMap } from "rxjs/operators"; +import { BaseHttpDataSourceOptionsBuilder } from "./BaseHttpDataSourceOptionsBuilder"; + +export class SingleDataSourceOptionsBuilder + extends BaseHttpDataSourceOptionsBuilder +{ + private _beforeRead: (query: IQueryCriteria) => Observable; + + constructor(http: HttpClient) { + super(http); + } + + public queryUrlWithGet(url: string) { + this._query = { + adapter: { + handle: (query: IQueryCriteria) => { + const finalBeforeRead = this._beforeRead || ((query: IQueryCriteria) => of({})); + return finalBeforeRead(query) + .pipe( + switchMap(finalQuery => { + return this.http.get(url, { + params: this.convertToParams(finalQuery) + }).pipe( + map(result => { + return & IQueryExecutionGroupResult> + { + totalRecords: result == null ? 0 : 1, + data: [result] + }; + }) + ) + }) + ); + } + } + } + + return this; + } + + protected convertToParams(finalQuery: TQuery) + { + return Object.keys(finalQuery).reduce((prev, key) => { + prev[key] = finalQuery[key]; + return prev; + }, {} as { [param: string]: string | string[]; }); + } + + public queryPostUrl(url: string) { + this._query = { + adapter: { + handle: (query: IQueryCriteria) => { + const finalBeforeRead = this._beforeRead || ((_: IQueryCriteria) => of({})); + return finalBeforeRead(query) + .pipe( + switchMap(finalQuery => { + return this.http.post(url, finalQuery).pipe( + map(result => { + return & IQueryExecutionGroupResult> + { + totalRecords: result == null ? 0 : 1, + data: [result] + }; + }) + ) + }) + ); + } + } + } + + return this; + } + + public queryHandler(queryHandler: (query: IQueryCriteria) => Observable) { + this._query = { + adapter: { + handle: (query: TQuery) => { + const finalBeforeRead = this._beforeRead || (t => of({})); + return finalBeforeRead(query) + .pipe( + switchMap(finalQuery => { + return queryHandler(finalQuery).pipe( + map(result => { + return & IQueryExecutionGroupResult>{ + totalRecords: result == null ? 0 : 1, + data: [result] + }; + }) + ) + }) + ); + } + } + } + + return this; + } +}