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