1+ import Operator from '../Operator' ;
2+ import Observer from '../Observer' ;
3+ import Subscriber from '../Subscriber' ;
4+ import Observable from '../Observable' ;
5+ import Subject from '../Subject' ;
6+ import Map from '../util/Map' ;
7+ import FastMap from '../util/FastMap' ;
8+
9+ import tryCatch from '../util/tryCatch' ;
10+ import { errorObject } from '../util/errorObject' ;
11+ import bindCallback from '../util/bindCallback' ;
12+
13+ export default function groupBy < T , R > ( keySelector : ( value : T ) => string ,
14+ elementSelector ?: ( value : T ) => R ,
15+ durationSelector ?: ( grouped : GroupSubject < R > ) => Observable < any > ) : Observable < GroupSubject < R > >
16+ {
17+ return this . lift ( new GroupByOperator < T , R > ( keySelector , durationSelector , elementSelector ) ) ;
18+ }
19+
20+ export class GroupByOperator < T , R > extends Operator < T , R > {
21+ constructor ( private keySelector : ( value : T ) => string ,
22+ private durationSelector ?: ( grouped : GroupSubject < R > ) => Observable < any > ,
23+ private elementSelector ?: ( value : T ) => R ) {
24+ super ( ) ;
25+ }
26+
27+ call ( observer : Observer < R > ) : Observer < T > {
28+ return new GroupBySubscriber < T , R > ( observer , this . keySelector , this . durationSelector , this . elementSelector ) ;
29+ }
30+ }
31+
32+ export class GroupBySubscriber < T , R > extends Subscriber < T > {
33+ private groups = null ;
34+
35+ constructor ( destination : Observer < R > , private keySelector : ( value : T ) => string ,
36+ private durationSelector ?: ( grouped : GroupSubject < R > ) => Observable < any > ,
37+ private elementSelector ?: ( value : T ) => R ) {
38+ super ( destination ) ;
39+ }
40+
41+ _next ( x : T ) {
42+ let key = tryCatch ( this . keySelector ) ( x ) ;
43+ if ( key === errorObject ) {
44+ this . error ( key . e ) ;
45+ } else {
46+ let groups = this . groups ;
47+ const elementSelector = this . elementSelector ;
48+ const durationSelector = this . durationSelector ;
49+
50+ if ( ! groups ) {
51+ groups = this . groups = typeof key === 'string' ? new FastMap ( ) : new Map ( ) ;
52+ }
53+
54+ let group : GroupSubject < R > = groups . get ( key ) ;
55+
56+ if ( ! group ) {
57+ groups . set ( key , group = new GroupSubject ( key ) ) ;
58+
59+ if ( durationSelector ) {
60+ let duration = tryCatch ( durationSelector ) ( group ) ;
61+ if ( duration === errorObject ) {
62+ this . error ( duration . e ) ;
63+ } else {
64+ this . add ( duration . subscribe ( new GroupDurationSubscriber ( group , this ) ) ) ;
65+ }
66+ }
67+
68+ this . destination . next ( group ) ;
69+ }
70+
71+ if ( elementSelector ) {
72+ let value = tryCatch ( elementSelector ) ( x )
73+ if ( value === errorObject ) {
74+ group . error ( value . e ) ;
75+ } else {
76+ group . next ( value ) ;
77+ }
78+ } else {
79+ group . next ( x ) ;
80+ }
81+ }
82+ }
83+
84+ _error ( err : any ) {
85+ const groups = this . groups ;
86+ if ( groups ) {
87+ groups . forEach ( ( group , key ) => {
88+ group . error ( err ) ;
89+ this . removeGroup ( key ) ;
90+ } ) ;
91+ }
92+ this . destination . error ( err ) ;
93+ }
94+
95+ _complete ( ) {
96+ const groups = this . groups ;
97+ if ( groups ) {
98+ groups . forEach ( ( group , key ) => {
99+ group . complete ( ) ;
100+ this . removeGroup ( group ) ;
101+ } ) ;
102+ }
103+ this . destination . complete ( ) ;
104+ }
105+
106+ removeGroup ( key : string ) {
107+ this . groups [ key ] = null ;
108+ }
109+ }
110+
111+ export class GroupSubject < T > extends Subject < T > {
112+ constructor ( public key : string ) {
113+ super ( ) ;
114+ }
115+ }
116+
117+ export class GroupDurationSubscriber < T > extends Subscriber < T > {
118+ constructor ( private group : GroupSubject < T > , private parent :GroupBySubscriber < any , T > ) {
119+ super ( null ) ;
120+ }
121+
122+ _next ( value : T ) {
123+ const group = this . group ;
124+ group . complete ( ) ;
125+ this . parent . removeGroup ( group . key ) ;
126+ }
127+
128+ _error ( err : any ) {
129+ const group = this . group ;
130+ group . error ( err ) ;
131+ this . parent . removeGroup ( group . key ) ;
132+ }
133+
134+ _complete ( ) {
135+ const group = this . group ;
136+ group . complete ( ) ;
137+ this . parent . removeGroup ( group . key ) ;
138+ }
139+ }
0 commit comments