From 0c3afe53b132578099ed9236dab189a4f0e351e6 Mon Sep 17 00:00:00 2001 From: Sylvain Tissot Date: Fri, 24 May 2019 12:35:05 +0200 Subject: [PATCH 1/6] Add support for form async validators + unique custom validator --- .../lib/services/abstract-model.service.ts | 73 ++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/projects/natural/src/lib/services/abstract-model.service.ts b/projects/natural/src/lib/services/abstract-model.service.ts index 8fe3f8c9..e3465680 100644 --- a/projects/natural/src/lib/services/abstract-model.service.ts +++ b/projects/natural/src/lib/services/abstract-model.service.ts @@ -1,4 +1,4 @@ -import { ValidatorFn } from '@angular/forms'; +import gql from 'graphql-tag'; import { Apollo } from 'apollo-angular'; import { NetworkStatus } from 'apollo-client'; import { FetchResult } from 'apollo-link'; @@ -10,11 +10,16 @@ import { NaturalFormControl } from '../classes/form-control'; import { NaturalQueryVariablesManager } from '../classes/query-variable-manager'; import { NaturalUtility } from '../classes/utility'; import { Literal } from '../types/types'; +import {AbstractControl, AsyncValidatorFn, ValidationErrors, ValidatorFn} from '@angular/forms'; export interface FormValidators { [key: string]: ValidatorFn[]; } +export interface FormAsyncValidators { + [key: string]: AsyncValidatorFn[]; +} + export interface VariablesWithInput { input: Literal; } @@ -67,6 +72,13 @@ export abstract class NaturalAbstractModelService): Observable { + const plural = NaturalUtility.makePlural(this.name); + let query = 'query Count' + NaturalUtility.upperCaseFirstLetter(plural); + query += '($filter: ' + NaturalUtility.upperCaseFirstLetter(this.name) + 'Filter) {'; + query += plural + '(filter: $filter, pagination: {pageSize: 0}) { length } }'; + query = gql(query); + return this.apollo.query({ + query: query, + variables: queryVariablesManager.variables.value, + }).pipe( + map((result) => { + return result.data[plural].length as number; + }), + ); + } + + public uniqueValidator(fieldName: string): AsyncValidatorFn { + return (control: AbstractControl): Observable => { + if (control.value) { + const qvm = new NaturalQueryVariablesManager(); + const condition = {}; + condition[fieldName] = {equal: {value: control.value}}; + const variables: any = { + pagination: {pageIndex: 0, pageSize: 0}, + filter: {groups: [{conditions: [condition]}]}, + }; + qvm.set('variables', variables); + this.count(qvm).pipe( + map((count: number) => { + return count > 0 ? {existingItems: count} : null; + }), + ); + } + return of(null); + }; + } + /** * Return empty object with some default values from server perspective * From c09298e1cff1bf4c8232bac1b2629c3d4f55dcd2 Mon Sep 17 00:00:00 2001 From: Sylvain Tissot Date: Fri, 24 May 2019 14:38:20 +0200 Subject: [PATCH 2/6] uniqueValidator: fix Observable not returned --- projects/natural/src/lib/services/abstract-model.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/natural/src/lib/services/abstract-model.service.ts b/projects/natural/src/lib/services/abstract-model.service.ts index e3465680..41af5b4e 100644 --- a/projects/natural/src/lib/services/abstract-model.service.ts +++ b/projects/natural/src/lib/services/abstract-model.service.ts @@ -515,7 +515,7 @@ export abstract class NaturalAbstractModelService { return count > 0 ? {existingItems: count} : null; }), From 820758388f1655d57043543772ac8d0b14a6061d Mon Sep 17 00:00:00 2001 From: Sylvain Tissot Date: Tue, 28 May 2019 15:50:09 +0200 Subject: [PATCH 3/6] Move unique validator to a separate NaturalValidators class --- .../src/lib/classes/abstract-detail.ts | 2 +- .../natural/src/lib/classes/validators.ts | 42 +++++++++++++++++++ .../lib/services/abstract-model.service.ts | 32 +++++--------- projects/natural/src/public-api.ts | 1 + 4 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 projects/natural/src/lib/classes/validators.ts diff --git a/projects/natural/src/lib/classes/abstract-detail.ts b/projects/natural/src/lib/classes/abstract-detail.ts index 492a21a0..ae25d2e7 100644 --- a/projects/natural/src/lib/classes/abstract-detail.ts +++ b/projects/natural/src/lib/classes/abstract-detail.ts @@ -36,7 +36,7 @@ export class NaturalAbstractDetail): AsyncValidatorFn { + + const validator = (control: AbstractControl): Observable => { + + const condition = {}; + + if (control.value) { + + condition[fieldName] = {equal: {value: control.value}}; + const variables: any = { + pagination: {pageIndex: 0, pageSize: 0}, + filter: {groups: [{conditions: [condition]}]}, + }; + + const qvm = new NaturalQueryVariablesManager(); + qvm.set('variables', variables); + + return modelService.count(qvm).pipe( + map((count: number) => { + return count > 0 ? {duplicateValue: count} : null; + }), + ); + } + + return of(null); + }; + return validator; + } +} diff --git a/projects/natural/src/lib/services/abstract-model.service.ts b/projects/natural/src/lib/services/abstract-model.service.ts index 41af5b4e..a5827e41 100644 --- a/projects/natural/src/lib/services/abstract-model.service.ts +++ b/projects/natural/src/lib/services/abstract-model.service.ts @@ -10,7 +10,7 @@ import { NaturalFormControl } from '../classes/form-control'; import { NaturalQueryVariablesManager } from '../classes/query-variable-manager'; import { NaturalUtility } from '../classes/utility'; import { Literal } from '../types/types'; -import {AbstractControl, AsyncValidatorFn, ValidationErrors, ValidatorFn} from '@angular/forms'; +import {AsyncValidatorFn, ValidatorFn} from '@angular/forms'; export interface FormValidators { [key: string]: ValidatorFn[]; @@ -86,6 +86,13 @@ export abstract class NaturalAbstractModelService): Observable { const plural = NaturalUtility.makePlural(this.name); @@ -504,27 +513,6 @@ export abstract class NaturalAbstractModelService => { - if (control.value) { - const qvm = new NaturalQueryVariablesManager(); - const condition = {}; - condition[fieldName] = {equal: {value: control.value}}; - const variables: any = { - pagination: {pageIndex: 0, pageSize: 0}, - filter: {groups: [{conditions: [condition]}]}, - }; - qvm.set('variables', variables); - return this.count(qvm).pipe( - map((count: number) => { - return count > 0 ? {existingItems: count} : null; - }), - ); - } - return of(null); - }; - } - /** * Return empty object with some default values from server perspective * diff --git a/projects/natural/src/public-api.ts b/projects/natural/src/public-api.ts index 045f6ff0..6333dbdb 100644 --- a/projects/natural/src/public-api.ts +++ b/projects/natural/src/public-api.ts @@ -12,6 +12,7 @@ export * from './lib/classes/data-source'; export * from './lib/classes/form-control'; export * from './lib/classes/query-variable-manager'; export * from './lib/classes/utility'; +export * from './lib/classes/validators'; export * from './lib/services/abstract-model.service'; export * from './lib/services/enum.service'; From b45927f0cf121efcbf5d8dd736e3d4228249d0ae Mon Sep 17 00:00:00 2001 From: Sylvain Tissot Date: Tue, 28 May 2019 16:16:38 +0200 Subject: [PATCH 4/6] Lint fixing --- projects/natural/src/lib/classes/abstract-detail.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/projects/natural/src/lib/classes/abstract-detail.ts b/projects/natural/src/lib/classes/abstract-detail.ts index ae25d2e7..90e4fcff 100644 --- a/projects/natural/src/lib/classes/abstract-detail.ts +++ b/projects/natural/src/lib/classes/abstract-detail.ts @@ -36,7 +36,10 @@ export class NaturalAbstractDetail Date: Tue, 28 May 2019 17:31:31 +0200 Subject: [PATCH 5/6] Add test for `NaturalAbstractModelService.count()` --- .../services/abstract-model.service.spec.ts | 18 ++++++++++++++++++ .../src/lib/testing/mock-apollo.provider.ts | 1 + 2 files changed, 19 insertions(+) diff --git a/projects/natural/src/lib/services/abstract-model.service.spec.ts b/projects/natural/src/lib/services/abstract-model.service.spec.ts index 9a21e773..50f1fbe0 100644 --- a/projects/natural/src/lib/services/abstract-model.service.spec.ts +++ b/projects/natural/src/lib/services/abstract-model.service.spec.ts @@ -2,6 +2,7 @@ import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { fakeAsync, inject, tick } from '@angular/core/testing'; import { NaturalAbstractModelService } from './abstract-model.service'; import { NaturalQueryVariablesManager } from '../classes/query-variable-manager'; +import { MockApolloProvider } from "../testing/mock-apollo.provider"; import { Literal } from '../types/types'; // A shortcut for shorter lines @@ -148,6 +149,23 @@ export abstract class AbstractModelServiceSpec { expect(Object.keys(object).length).toBeGreaterThan(keysAfterCreation); // should show created + updated objects merged })), ); + + it('should count existing values', + fakeAsync(inject([serviceClass], (service: ModelService) => { + const qvm = new NaturalQueryVariablesManager(); + let variables: any = { + pagination: {pageIndex: 0, pageSize: 0}, + filter: {groups: [{conditions: [{slug: 'test string'}]}]}, + }; + qvm.set('variables', variables); + expect(() => service.count(qvm).subscribe()).toEqual(1); + + variables['filter']['groups'][0]['conditions'][0]['slug'] = 'other string'; + qvm.set('variables', variables); + expect(() => service.count(qvm).subscribe()).toEqual(0); + + })), + ); } private static expectNotConfiguredOrEqual(expectSuccess: boolean, diff --git a/projects/natural/src/lib/testing/mock-apollo.provider.ts b/projects/natural/src/lib/testing/mock-apollo.provider.ts index fbe6b5d0..dde91738 100644 --- a/projects/natural/src/lib/testing/mock-apollo.provider.ts +++ b/projects/natural/src/lib/testing/mock-apollo.provider.ts @@ -33,6 +33,7 @@ const typeDefs = ` type Post { id: ID! + slug: String blog: Blog } From e3a88d7fd9b8f9172a6b9c123db8dbb752dfd2a5 Mon Sep 17 00:00:00 2001 From: Sylvain Tissot Date: Tue, 28 May 2019 17:40:23 +0200 Subject: [PATCH 6/6] Lint fixing --- .../natural/src/lib/services/abstract-model.service.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/projects/natural/src/lib/services/abstract-model.service.spec.ts b/projects/natural/src/lib/services/abstract-model.service.spec.ts index 50f1fbe0..549775da 100644 --- a/projects/natural/src/lib/services/abstract-model.service.spec.ts +++ b/projects/natural/src/lib/services/abstract-model.service.spec.ts @@ -2,7 +2,6 @@ import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { fakeAsync, inject, tick } from '@angular/core/testing'; import { NaturalAbstractModelService } from './abstract-model.service'; import { NaturalQueryVariablesManager } from '../classes/query-variable-manager'; -import { MockApolloProvider } from "../testing/mock-apollo.provider"; import { Literal } from '../types/types'; // A shortcut for shorter lines @@ -153,7 +152,7 @@ export abstract class AbstractModelServiceSpec { it('should count existing values', fakeAsync(inject([serviceClass], (service: ModelService) => { const qvm = new NaturalQueryVariablesManager(); - let variables: any = { + const variables: any = { pagination: {pageIndex: 0, pageSize: 0}, filter: {groups: [{conditions: [{slug: 'test string'}]}]}, };