Skip to content

Commit

Permalink
feat: static type check about prerequest
Browse files Browse the repository at this point in the history
using generic to define type of prerequest result that point out which this data flow need

BREAKING CHANGE: some of DataFlow need specify 'Tpre'. simplest way is that set it as
`BareFlowPreNode`.
  • Loading branch information
ElonH committed May 16, 2020
1 parent 9e19149 commit 6c1cc80
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 59 deletions.
31 changes: 21 additions & 10 deletions src/app/@dataflow/core/bare-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BareFlow, DataFlowNode } from './bare-flow';
import { BareFlow, DataFlowNode, BareFlowPreNode } from './bare-flow';
import { TestScheduler } from 'rxjs/testing';
import { Observable, of } from 'rxjs';

Expand All @@ -19,7 +19,7 @@ describe('BareFlow', () => {
const pre = cold('a----', values);
const expected = 'a----';

const rst = new (class extends BareFlow {
const rst = new (class extends BareFlow<BareFlowPreNode> {
public prerequest$ = pre;
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
throw new Error('Method not implemented.');
Expand All @@ -33,14 +33,18 @@ describe('BareFlow', () => {
it('request twice, but got once only', () => {
scheduler.run((helpers) => {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const values: { [id: string]: DataFlowNode } = {
interface TestPreNode {
a?: number;
b?: number;
}
const values: { [id: string]: [TestPreNode, []] } = {
a: [{ a: 555 }, []],
b: [{ b: 123 }, []],
};
const pre = cold('a----', values);
const expected = 'b----';

const rst = new (class extends BareFlow {
const rst = new (class extends BareFlow<TestPreNode> {
public prerequest$ = pre;
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
expect(pre).toEqual(values.a);
Expand All @@ -54,15 +58,19 @@ describe('BareFlow', () => {
});
it('prerequest twice(same value), but got once only', () => {
scheduler.run((helpers) => {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const values: { [id: string]: DataFlowNode } = {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
interface TestPreNode {
a?: number;
b?: number;
}
const values: { [id: string]: [TestPreNode, []] } = {
a: [{ a: 555 }, []],
b: [{ b: 123 }, []],
};
const pre = cold('a--a-', values);
const expected = 'b----';

const rst = new (class extends BareFlow {
const rst = new (class extends BareFlow<TestPreNode> {
public prerequest$ = pre;
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
return of(values.b);
Expand All @@ -75,8 +83,11 @@ describe('BareFlow', () => {
});
it('prerequest twice(different value), got twice', () => {
scheduler.run((helpers) => {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const values: { [id: string]: DataFlowNode } = {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
interface TestPreNode {
ab: number;
}
const values: { [id: string]: [TestPreNode, []] } = {
a: [{ ab: 555 }, []],
b: [{ ab: 123 }, []],
c: [{ ab: 556 }, []],
Expand All @@ -85,7 +96,7 @@ describe('BareFlow', () => {
const pre = cold('a--b-', values);
const expected = 'c--d-';

const rst = new (class extends BareFlow {
const rst = new (class extends BareFlow<TestPreNode> {
public prerequest$ = pre;
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
return of([{ ab: pre[0]['ab'] + 1 }, []]);
Expand Down
8 changes: 5 additions & 3 deletions src/app/@dataflow/core/bare-flow.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Observable, of } from 'rxjs';
import { switchMap, take, tap, startWith, distinctUntilChanged, skipWhile } from 'rxjs/operators';

export type DataFlowNode = [object, Error[]];
export interface BareFlowPreNode {};
export type DataFlowNode = [BareFlowPreNode, Error[]];
export type CombErr<T> = [T, Error[]];

export abstract class BareFlow {
public abstract prerequest$: Observable<DataFlowNode>;
export abstract class BareFlow<Tpre extends BareFlowPreNode> {
public abstract prerequest$: Observable<CombErr<Tpre>>;
protected abstract request(pre: DataFlowNode): Observable<DataFlowNode>;
private bareData$: Observable<DataFlowNode>;
private deployed = false;
Expand Down
10 changes: 5 additions & 5 deletions src/app/@dataflow/core/cache-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CacheFlow } from './cache-flow';
import { TestScheduler } from 'rxjs/testing';
import { DataFlowNode } from './bare-flow';
import { DataFlowNode, BareFlowPreNode } from './bare-flow';
import { Observable, of } from 'rxjs';

describe('CacheFlow', () => {
Expand All @@ -16,7 +16,7 @@ describe('CacheFlow', () => {
});
it('prerequest twice(different value), request same value, only output onece', () => {
scheduler.run((helpers) => {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const values: { [id: string]: DataFlowNode } = {
a: [{ ab: 555 }, []],
b: [{ ab: 123 }, []],
Expand All @@ -27,7 +27,7 @@ describe('CacheFlow', () => {
const expectedOutput = 'k----';
const expectedSupers = 'c----';

const rst = new (class extends CacheFlow {
const rst = new (class extends CacheFlow<BareFlowPreNode> {
protected cacheSupport: boolean = true;
protected cachePath: string = 'foo';
public prerequest$ = pre;
Expand Down Expand Up @@ -56,7 +56,7 @@ describe('CacheFlow', () => {
const expectedOutput = 'k----';
const expectedSupers = 'c----';
const expectedSuper2 = 'd----';
class TestCache extends CacheFlow {
class TestCache extends CacheFlow<BareFlowPreNode> {
protected cacheSupport: boolean = true;
protected cachePath: string = 'foo';
public prerequest$ = null;
Expand Down Expand Up @@ -95,7 +95,7 @@ describe('CacheFlow', () => {
const expectedOutput = 'c--d-';
const expectedSupers = 'e--f-';

const rst = new (class extends CacheFlow {
const rst = new (class extends CacheFlow<BareFlowPreNode> {
protected cacheSupport: boolean = false;
protected cachePath: string = 'foo';
public prerequest$ = pre;
Expand Down
4 changes: 2 additions & 2 deletions src/app/@dataflow/core/cache-flow.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { DataFlowNode } from './bare-flow';
import { DataFlowNode, BareFlowPreNode } from './bare-flow';
import { Observable, iif, of } from 'rxjs';
import { SupersetFlow } from './superset-flow';
import { tap, take, map } from 'rxjs/operators';

export abstract class CacheFlow extends SupersetFlow {
export abstract class CacheFlow<Tpre extends BareFlowPreNode> extends SupersetFlow<Tpre> {
protected abstract requestCache(pre: DataFlowNode): Observable<DataFlowNode>;
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
return iif(
Expand Down
4 changes: 2 additions & 2 deletions src/app/@dataflow/core/superset-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SupersetFlow } from './superset-flow';
import { TestScheduler } from 'rxjs/testing';
import { DataFlowNode } from './bare-flow';
import { DataFlowNode, BareFlowPreNode } from './bare-flow';
import { Observable, of } from 'rxjs';

describe('SupersetFlow', () => {
Expand All @@ -23,7 +23,7 @@ describe('SupersetFlow', () => {
const pre = cold('a--b-', values);
const expected = 'c--d-';

const rst = new (class extends SupersetFlow {
const rst = new (class extends SupersetFlow<BareFlowPreNode> {
public prerequest$ = pre;
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
return of([{ cd: pre[0]['ab'] + 1 }, []]);
Expand Down
4 changes: 2 additions & 2 deletions src/app/@dataflow/core/superset-flow.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BareFlow, DataFlowNode } from './bare-flow';
import { BareFlow, DataFlowNode, BareFlowPreNode } from './bare-flow';
import { Observable } from 'rxjs';
import {
tap,
Expand All @@ -10,7 +10,7 @@ import {
map,
} from 'rxjs/operators';

export abstract class SupersetFlow extends BareFlow {
export abstract class SupersetFlow<Tpre extends BareFlowPreNode> extends BareFlow<Tpre> {
private boostrapPrerequest$: Observable<DataFlowNode>;
private boostrapPrerequest: DataFlowNode;
public deploy() {
Expand Down
29 changes: 15 additions & 14 deletions src/app/@dataflow/extra/name-validation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NameValidation } from './name-validation';
import { NameValidation, NameValidationPreNode, NameValidationNode } from './name-validation';
import { TestScheduler } from 'rxjs/testing';
import { DataFlowNode } from '../core';
import { CombErr } from '../core';
import { Observable } from 'rxjs';

describe('NameValidation', () => {
let scheduler: TestScheduler;
Expand All @@ -13,11 +14,11 @@ describe('NameValidation', () => {
it('normal', () => {
scheduler.run((helpers) => {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const values = {
a: [{ users: [{ name: '123' }], currentName: 'asd' }, []] as DataFlowNode,
b: [{ nameValid: true }, []] as DataFlowNode,
const values: { [id: string]: CombErr<NameValidationPreNode | NameValidationNode> } = {
a: [{ users: [{ name: '123', url: '' }], currentName: 'asd' }, []],
b: [{ nameValid: true }, []],
};
const pre = cold('a----', values);
const pre = cold('a----', values) as Observable<CombErr<NameValidationPreNode>>;
const expected = 'b----';

const rst = new (class extends NameValidation {
Expand All @@ -31,11 +32,11 @@ describe('NameValidation', () => {
it('not allow empty', () => {
scheduler.run((helpers) => {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const values = {
a: [{ users: [], currentName: '' }, []] as DataFlowNode,
b: [{}, [new Error('You must enter a value')]] as DataFlowNode,
const values: { [id: string]: CombErr<NameValidationPreNode | NameValidationNode> } = {
a: [{ users: [], currentName: '' }, []],
b: [{}, [new Error('You must enter a value')]],
};
const pre = cold('a----', values);
const pre = cold('a----', values) as Observable<CombErr<NameValidationPreNode>>;
const expected = 'b----';

const rst = new (class extends NameValidation {
Expand All @@ -49,11 +50,11 @@ describe('NameValidation', () => {
it('not allow duplicate name', () => {
scheduler.run((helpers) => {
const { cold, hot, expectObservable, expectSubscriptions, flush } = helpers;
const values = {
a: [{ users: [{ name: '123' }], currentName: '123' }, []] as DataFlowNode,
b: [{}, [new Error('This name already exists')]] as DataFlowNode,
const values: { [id: string]: CombErr<NameValidationPreNode | NameValidationNode> } = {
a: [{ users: [{ name: '123', url: '' }], currentName: '123' }, []],
b: [{}, [new Error('This name already exists')]],
};
const pre = cold('a----', values);
const pre = cold('a----', values) as Observable<CombErr<NameValidationPreNode>>;
const expected = 'b----';

const rst = new (class extends NameValidation {
Expand Down
15 changes: 11 additions & 4 deletions src/app/@dataflow/extra/name-validation.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { SupersetFlow, DataFlowNode } from '../core';
import { SupersetFlow, DataFlowNode, BareFlowPreNode } from '../core';
import { Observable, of } from 'rxjs';
import { IUser } from './users-flow';
import { IUser, UsersFlowNode } from './users-flow';

export abstract class NameValidation extends SupersetFlow {
// public prerequest$: Observable<DataFlowNode>;
export interface NameValidationPreNode extends UsersFlowNode {
currentName: string;
}

export interface NameValidationNode extends BareFlowPreNode {
nameValid?: boolean;
}

export abstract class NameValidation extends SupersetFlow<NameValidationPreNode> {
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
const curName = pre[0]['currentName'];
if (curName === '') return of([{}, [new Error('You must enter a value')]]);
Expand Down
6 changes: 3 additions & 3 deletions src/app/@dataflow/extra/users-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UsersFlow, IUser } from './users-flow';
import { UsersFlow, IUser, UsersFlowNode } from './users-flow';
import { TestScheduler } from 'rxjs/testing';
import { DataFlowNode } from '../core';
import { map } from 'rxjs/operators';
Expand Down Expand Up @@ -42,7 +42,7 @@ describe('UsersFlow', () => {
const expected = 'b-b--';

const rst = new (class extends UsersFlow {
public prerequest$ = pre.pipe(map(() => [{}, []] as DataFlowNode));
public prerequest$ = pre.pipe(map((): DataFlowNode => [{}, []]));
})();

UsersFlow.setAll([]);
Expand All @@ -67,7 +67,7 @@ describe('UsersFlow', () => {
const expected = 'b-b--';

const rst = new (class extends UsersFlow {
public prerequest$ = pre.pipe(map(() => [{}, []] as DataFlowNode));
public prerequest$ = pre.pipe(map((): DataFlowNode => [{}, []]));
})();

UsersFlow.setAll([
Expand Down
19 changes: 12 additions & 7 deletions src/app/@dataflow/extra/users-flow.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { Observable, of } from 'rxjs';
import { IRcloneServer } from '../rclone/noop-auth';
import { BareFlow, DataFlowNode } from '../core';
import { BareFlow, DataFlowNode, BareFlowPreNode, CombErr } from '../core';

export interface IUser extends IRcloneServer {
name: string;
}

export type UsersFlowNode = [{ users: IUser[] }, []];
// export type UsersFlowNode = [{ users: IUser[] }, Error[]];
export interface UsersFlowNode extends BareFlowPreNode {
users: IUser[];
}

export abstract class UsersFlow extends BareFlow {
public static readonly defaultUser: IUser[] = [{ name: 'localhost', url: 'http://localhost:5572' }];
export abstract class UsersFlow extends BareFlow<BareFlowPreNode> {
public static readonly defaultUser: IUser[] = [
{ name: 'localhost', url: 'http://localhost:5572' },
];
protected request(pre: DataFlowNode): Observable<DataFlowNode> {
const dataRaw = localStorage.getItem('users');
if (dataRaw) return of([{ users: JSON.parse(dataRaw) }, []]);
Expand All @@ -22,7 +27,7 @@ export abstract class UsersFlow extends BareFlow {
public static set(user: IUser) {
const dataRaw = localStorage.getItem('users');
if (dataRaw) {
const data = JSON.parse(dataRaw) as IUser[];
const data = JSON.parse(dataRaw) as IUser[];
for (let i = 0; i < data.length; i++) {
if (data[i].name === user.name) {
data[i] = user;
Expand All @@ -38,8 +43,8 @@ export abstract class UsersFlow extends BareFlow {
data.push(user);
localStorage.setItem('users', JSON.stringify(data));
}
public getOutput(): Observable<UsersFlowNode> {
return super.getOutput() as Observable<UsersFlowNode>;
public getOutput(): Observable<CombErr<UsersFlowNode>> {
return super.getOutput() as Observable<CombErr<UsersFlowNode>>;
}
public static purge() {
localStorage.removeItem('users');
Expand Down
14 changes: 8 additions & 6 deletions src/app/pages/user/config/config.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
import { Observable } from 'rxjs';
import { UsersFlowNode, NameValidation } from 'src/app/@dataflow/extra';
import { UsersFlowNode, NameValidation, NameValidationPreNode } from 'src/app/@dataflow/extra';
import { FormControl } from '@angular/forms';
import { DataFlowNode } from 'src/app/@dataflow/core';
import { withLatestFrom, map, startWith } from 'rxjs/operators';
import { CombErr } from 'src/app/@dataflow/core';

@Component({
selector: 'user-config',
Expand Down Expand Up @@ -123,12 +123,14 @@ export class ConfigComponent implements OnInit {
ngOnInit(): void {
const outer = this;
this.nameValidation$ = new (class extends NameValidation {
public prerequest$: Observable<DataFlowNode> = outer.name.valueChanges.pipe(
public prerequest$ = outer.name.valueChanges.pipe(
startWith(''),
withLatestFrom(outer.users$),
map(([curName, usersNode]) => {
return [{ ...usersNode[0], currentName: curName }, usersNode[1]];
})
map(
([curName, usersNode]): CombErr<NameValidationPreNode> => {
return [{ ...usersNode[0], currentName: curName }, usersNode[1]];
}
)
);
})();
this.nameValidation$.deploy();
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/user/user.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class UserComponent implements OnInit {
ngOnInit(): void {
const outer = this;
this.usersFlow$ = new (class extends UsersFlow {
public prerequest$ = outer.userSubject.pipe(map(() => [{}, []] as DataFlowNode));
public prerequest$ = outer.userSubject.pipe(map((): DataFlowNode => [{}, []]));
})();
this.usersFlow$.deploy();

Expand Down

0 comments on commit 6c1cc80

Please sign in to comment.