@eleven-am/pondsocket 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +28 -0
- package/.idea/modules.xml +8 -0
- package/.idea/pondsocket.iml +12 -0
- package/LICENSE +674 -0
- package/base.d.ts +1 -0
- package/base.js +17 -0
- package/client.d.ts +1 -0
- package/client.js +17 -0
- package/index.d.ts +1 -0
- package/index.js +17 -0
- package/jest.config.js +11 -0
- package/package.json +48 -0
- package/pondBase/baseClass.d.ts +37 -0
- package/pondBase/baseClass.js +111 -0
- package/pondBase/baseClass.test.js +73 -0
- package/pondBase/enums.d.ts +9 -0
- package/pondBase/enums.js +14 -0
- package/pondBase/index.d.ts +6 -0
- package/pondBase/index.js +22 -0
- package/pondBase/pondBase.d.ts +41 -0
- package/pondBase/pondBase.js +60 -0
- package/pondBase/pondBase.test.js +101 -0
- package/pondBase/pubSub.d.ts +73 -0
- package/pondBase/pubSub.js +138 -0
- package/pondBase/pubSub.test.js +309 -0
- package/pondBase/simpleBase.d.ts +131 -0
- package/pondBase/simpleBase.js +211 -0
- package/pondBase/simpleBase.test.js +153 -0
- package/pondBase/types.d.ts +2 -0
- package/pondBase/types.js +2 -0
- package/pondClient/channel.d.ts +66 -0
- package/pondClient/channel.js +152 -0
- package/pondClient/index.d.ts +2 -0
- package/pondClient/index.js +18 -0
- package/pondClient/socket.d.ts +42 -0
- package/pondClient/socket.js +116 -0
- package/pondSocket/channel.d.ts +134 -0
- package/pondSocket/channel.js +287 -0
- package/pondSocket/channel.test.js +377 -0
- package/pondSocket/channelMiddleWare.d.ts +26 -0
- package/pondSocket/channelMiddleWare.js +36 -0
- package/pondSocket/endpoint.d.ts +90 -0
- package/pondSocket/endpoint.js +323 -0
- package/pondSocket/endpoint.test.js +513 -0
- package/pondSocket/enums.d.ts +19 -0
- package/pondSocket/enums.js +25 -0
- package/pondSocket/index.d.ts +7 -0
- package/pondSocket/index.js +23 -0
- package/pondSocket/pondChannel.d.ts +79 -0
- package/pondSocket/pondChannel.js +219 -0
- package/pondSocket/pondChannel.test.js +430 -0
- package/pondSocket/pondResponse.d.ts +25 -0
- package/pondSocket/pondResponse.js +120 -0
- package/pondSocket/pondSocket.d.ts +47 -0
- package/pondSocket/pondSocket.js +94 -0
- package/pondSocket/server.test.js +136 -0
- package/pondSocket/socketMiddleWare.d.ts +6 -0
- package/pondSocket/socketMiddleWare.js +32 -0
- package/pondSocket/types.d.ts +74 -0
- package/pondSocket/types.js +2 -0
- package/socket.d.ts +1 -0
- package/socket.js +17 -0
- package/tsconfig.eslint.json +5 -0
- package/tsconfig.json +90 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export declare class Subscription {
|
|
2
|
+
unsubscribe(): void;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export declare class Broadcast<T, A> {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @desc Subscribe to the broadcast
|
|
9
|
+
* @param handler - The handler to call when the broadcast is published
|
|
10
|
+
*/
|
|
11
|
+
subscribe(handler: (data: T) => A): Subscription;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @desc Publish to the broadcast
|
|
15
|
+
* @param data - The data to publish
|
|
16
|
+
*/
|
|
17
|
+
publish(data: T): A | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export declare class Subject<T, A> extends Broadcast<T, A> {
|
|
21
|
+
constructor(value: T);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @desc Get the current value of the subject
|
|
25
|
+
*/
|
|
26
|
+
get value(): T;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @desc Subscribe to the subject
|
|
30
|
+
* @param handler - The handler to call when the subject is published
|
|
31
|
+
*/
|
|
32
|
+
subscribe(handler: (data: T) => A): Subscription;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @desc Publish to the subject
|
|
36
|
+
* @param data - The data to publish
|
|
37
|
+
*/
|
|
38
|
+
publish(data: T): A | undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export declare class EventPubSub<T, A> {
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @desc Subscribe to the event subject
|
|
45
|
+
* @param event - The event to subscribe to
|
|
46
|
+
* @param handler - The handler to call when the event subject is published
|
|
47
|
+
*/
|
|
48
|
+
subscribe(event: string, handler: (data: T) => A): Subscription;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @desc Publish to the event subject
|
|
52
|
+
* @param event - The event to publish
|
|
53
|
+
* @param data - The data to publish
|
|
54
|
+
*/
|
|
55
|
+
publish(event: string, data: T): void;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @desc Subscribe to all events
|
|
59
|
+
* @param handler - The handler to call when the event subject is published
|
|
60
|
+
*/
|
|
61
|
+
subscribeAll(handler: (event: T) => A): Subscription;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @desc Complete the event subject
|
|
65
|
+
*/
|
|
66
|
+
complete(): void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @desc Subscribe to the event subject completion
|
|
70
|
+
* @param handler - The handler to call when the event subject is completed
|
|
71
|
+
*/
|
|
72
|
+
onComplete(handler: () => void): void;
|
|
73
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventPubSub = exports.Subject = exports.Broadcast = void 0;
|
|
4
|
+
class Broadcast {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._subscribers = new Set();
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @desc Subscribe to the broadcast
|
|
10
|
+
* @param handler - The handler to call when the broadcast is published
|
|
11
|
+
*/
|
|
12
|
+
subscribe(handler) {
|
|
13
|
+
this._subscribers.add(handler);
|
|
14
|
+
return {
|
|
15
|
+
/**
|
|
16
|
+
* @desc Unsubscribe from the broadcast
|
|
17
|
+
*/
|
|
18
|
+
unsubscribe: () => {
|
|
19
|
+
this._subscribers.delete(handler);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @desc Publish to the broadcast
|
|
25
|
+
* @param data - The data to publish
|
|
26
|
+
*/
|
|
27
|
+
publish(data) {
|
|
28
|
+
let result;
|
|
29
|
+
for (const subscriber of this._subscribers) {
|
|
30
|
+
result = subscriber(data);
|
|
31
|
+
if (result)
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.Broadcast = Broadcast;
|
|
38
|
+
class Subject extends Broadcast {
|
|
39
|
+
constructor(value) {
|
|
40
|
+
super();
|
|
41
|
+
this._value = value;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @desc Get the current value of the subject
|
|
45
|
+
*/
|
|
46
|
+
get value() {
|
|
47
|
+
return this._value;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* @desc Subscribe to the subject
|
|
51
|
+
* @param handler - The handler to call when the subject is published
|
|
52
|
+
*/
|
|
53
|
+
subscribe(handler) {
|
|
54
|
+
void handler(this._value);
|
|
55
|
+
return super.subscribe(handler);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* @desc Publish to the subject
|
|
59
|
+
* @param data - The data to publish
|
|
60
|
+
*/
|
|
61
|
+
publish(data) {
|
|
62
|
+
if (this._value !== data) {
|
|
63
|
+
this._value = data;
|
|
64
|
+
return super.publish(data);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.Subject = Subject;
|
|
69
|
+
class EventPubSub {
|
|
70
|
+
constructor() {
|
|
71
|
+
this._subscribers = new Set();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* @desc Subscribe to the event subject
|
|
75
|
+
* @param event - The event to subscribe to
|
|
76
|
+
* @param handler - The handler to call when the event subject is published
|
|
77
|
+
*/
|
|
78
|
+
subscribe(event, handler) {
|
|
79
|
+
const subscriber = (eventData) => {
|
|
80
|
+
if (eventData.type === event)
|
|
81
|
+
return handler(eventData.data);
|
|
82
|
+
return undefined;
|
|
83
|
+
};
|
|
84
|
+
this._subscribers.add(subscriber);
|
|
85
|
+
return {
|
|
86
|
+
/**
|
|
87
|
+
* @desc Unsubscribe from the event subject
|
|
88
|
+
*/
|
|
89
|
+
unsubscribe: () => {
|
|
90
|
+
this._subscribers.delete(subscriber);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* @desc Publish to the event subject
|
|
96
|
+
* @param event - The event to publish
|
|
97
|
+
* @param data - The data to publish
|
|
98
|
+
*/
|
|
99
|
+
publish(event, data) {
|
|
100
|
+
for (const subscriber of this._subscribers) {
|
|
101
|
+
void subscriber({ type: event, data });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* @desc Subscribe to all events
|
|
106
|
+
* @param handler - The handler to call when the event subject is published
|
|
107
|
+
*/
|
|
108
|
+
subscribeAll(handler) {
|
|
109
|
+
const subscriber = (eventData) => {
|
|
110
|
+
return handler(eventData.data);
|
|
111
|
+
};
|
|
112
|
+
this._subscribers.add(subscriber);
|
|
113
|
+
return {
|
|
114
|
+
/**
|
|
115
|
+
* @desc Unsubscribe from the event subject
|
|
116
|
+
*/
|
|
117
|
+
unsubscribe: () => {
|
|
118
|
+
this._subscribers.delete(subscriber);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* @desc Complete the event subject
|
|
124
|
+
*/
|
|
125
|
+
complete() {
|
|
126
|
+
this._subscribers.clear();
|
|
127
|
+
if (this._onComplete)
|
|
128
|
+
this._onComplete();
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* @desc Subscribe to the event subject completion
|
|
132
|
+
* @param handler - The handler to call when the event subject is completed
|
|
133
|
+
*/
|
|
134
|
+
onComplete(handler) {
|
|
135
|
+
this._onComplete = handler;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.EventPubSub = EventPubSub;
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const pubSub_1 = require("./pubSub");
|
|
4
|
+
describe('Broadcast', () => {
|
|
5
|
+
it('should be defined', () => {
|
|
6
|
+
expect(pubSub_1.Broadcast).toBeDefined();
|
|
7
|
+
});
|
|
8
|
+
it('should be a class', () => {
|
|
9
|
+
expect(pubSub_1.Broadcast).toBeInstanceOf(Function);
|
|
10
|
+
});
|
|
11
|
+
// Functionality tests
|
|
12
|
+
it('should publish a message to all subscribers', () => {
|
|
13
|
+
const broadcast = new pubSub_1.Broadcast();
|
|
14
|
+
const subscriber = jest.fn();
|
|
15
|
+
broadcast.subscribe(subscriber); // test with one subscriber
|
|
16
|
+
broadcast.publish('Hello');
|
|
17
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
18
|
+
});
|
|
19
|
+
it('should publish a message to all subscribers', () => {
|
|
20
|
+
const broadcast = new pubSub_1.Broadcast();
|
|
21
|
+
const subscriber1 = jest.fn();
|
|
22
|
+
const subscriber2 = jest.fn();
|
|
23
|
+
broadcast.subscribe(subscriber1); // test with two subscribers
|
|
24
|
+
broadcast.subscribe(subscriber2);
|
|
25
|
+
broadcast.publish('Hello');
|
|
26
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
27
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello');
|
|
28
|
+
});
|
|
29
|
+
it('should publish a message to all subscribers', () => {
|
|
30
|
+
// including subscribers that subscribe after the first message is published
|
|
31
|
+
const broadcast = new pubSub_1.Broadcast();
|
|
32
|
+
const subscriber1 = jest.fn();
|
|
33
|
+
const subscriber2 = jest.fn();
|
|
34
|
+
broadcast.subscribe(subscriber1);
|
|
35
|
+
broadcast.publish('Hello');
|
|
36
|
+
broadcast.subscribe(subscriber2);
|
|
37
|
+
broadcast.publish('Hello Again');
|
|
38
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
39
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello Again');
|
|
40
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello Again');
|
|
41
|
+
});
|
|
42
|
+
it('should unsubscribe a subscriber and thus not receive new message', () => {
|
|
43
|
+
const broadcast = new pubSub_1.Broadcast();
|
|
44
|
+
const subscriber1 = jest.fn();
|
|
45
|
+
const subscriber2 = jest.fn();
|
|
46
|
+
broadcast.subscribe(subscriber1);
|
|
47
|
+
broadcast.subscribe(subscriber2);
|
|
48
|
+
broadcast.publish('Hello');
|
|
49
|
+
const subscription = broadcast.subscribe(subscriber2);
|
|
50
|
+
subscription.unsubscribe();
|
|
51
|
+
broadcast.publish('Hello Again');
|
|
52
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
53
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello Again');
|
|
54
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello');
|
|
55
|
+
expect(subscriber2).not.toHaveBeenCalledWith('Hello Again');
|
|
56
|
+
});
|
|
57
|
+
it('should stop the broadcast midway if a subscription returns a value', () => {
|
|
58
|
+
const broadcast = new pubSub_1.Broadcast();
|
|
59
|
+
const subscriber1 = jest.fn();
|
|
60
|
+
const subscriber2 = jest.fn(() => true);
|
|
61
|
+
const subscriber3 = jest.fn();
|
|
62
|
+
broadcast.subscribe(subscriber1);
|
|
63
|
+
broadcast.subscribe(subscriber2);
|
|
64
|
+
broadcast.subscribe(subscriber3);
|
|
65
|
+
broadcast.publish('Hello');
|
|
66
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
67
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello');
|
|
68
|
+
expect(subscriber3).not.toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
it('should throw an error if one of its subscribers throws an error', () => {
|
|
71
|
+
const broadcast = new pubSub_1.Broadcast();
|
|
72
|
+
const subscriber1 = jest.fn();
|
|
73
|
+
const subscriber2 = jest.fn(() => {
|
|
74
|
+
throw new Error('Something went wrong');
|
|
75
|
+
});
|
|
76
|
+
const subscriber3 = jest.fn();
|
|
77
|
+
broadcast.subscribe(subscriber1);
|
|
78
|
+
broadcast.subscribe(subscriber2);
|
|
79
|
+
broadcast.subscribe(subscriber3);
|
|
80
|
+
expect(() => broadcast.publish('Hello')).toThrowError('Something went wrong');
|
|
81
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
82
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello');
|
|
83
|
+
expect(subscriber3).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('Subject', () => {
|
|
87
|
+
it('should be defined', () => {
|
|
88
|
+
expect(pubSub_1.Subject).toBeDefined();
|
|
89
|
+
});
|
|
90
|
+
it('should be a class', () => {
|
|
91
|
+
expect(pubSub_1.Subject).toBeInstanceOf(Function);
|
|
92
|
+
});
|
|
93
|
+
// Functionality tests
|
|
94
|
+
it('should publish a message to all subscribers', () => {
|
|
95
|
+
const subject = new pubSub_1.Subject('hi');
|
|
96
|
+
const subscriber = jest.fn();
|
|
97
|
+
subject.subscribe(subscriber); // test with one subscriber
|
|
98
|
+
subject.publish('Hello');
|
|
99
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
100
|
+
});
|
|
101
|
+
it('should publish a message to all subscribers', () => {
|
|
102
|
+
const subject = new pubSub_1.Subject('hi');
|
|
103
|
+
const subscriber1 = jest.fn();
|
|
104
|
+
const subscriber2 = jest.fn();
|
|
105
|
+
subject.subscribe(subscriber1); // test with two subscribers
|
|
106
|
+
subject.subscribe(subscriber2);
|
|
107
|
+
subject.publish('Hello');
|
|
108
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
109
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello');
|
|
110
|
+
});
|
|
111
|
+
it('should provide the initial value to new subscribers', () => {
|
|
112
|
+
const subject = new pubSub_1.Subject('hi');
|
|
113
|
+
const subscriber = jest.fn();
|
|
114
|
+
subject.subscribe(subscriber); // test with one subscriber
|
|
115
|
+
expect(subscriber).toHaveBeenCalledWith('hi');
|
|
116
|
+
});
|
|
117
|
+
it('should publish a message to all subscribers', () => {
|
|
118
|
+
// including subscribers that subscribe after the first message is published
|
|
119
|
+
const subject = new pubSub_1.Subject('hi');
|
|
120
|
+
const subscriber1 = jest.fn();
|
|
121
|
+
const subscriber2 = jest.fn();
|
|
122
|
+
subject.subscribe(subscriber1);
|
|
123
|
+
subject.publish('Hello');
|
|
124
|
+
subject.subscribe(subscriber2);
|
|
125
|
+
subject.publish('Hello Again');
|
|
126
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
127
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello Again');
|
|
128
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello Again');
|
|
129
|
+
});
|
|
130
|
+
it('should return the current value when the getter is called', () => {
|
|
131
|
+
const subject = new pubSub_1.Subject('hi');
|
|
132
|
+
expect(subject.value).toEqual('hi');
|
|
133
|
+
});
|
|
134
|
+
it('should throw an error if one of its subscribers throws an error', () => {
|
|
135
|
+
const subject = new pubSub_1.Subject('hi');
|
|
136
|
+
const subscriber1 = jest.fn();
|
|
137
|
+
const subscriber2 = jest.fn(() => {
|
|
138
|
+
throw new Error('Something went wrong');
|
|
139
|
+
});
|
|
140
|
+
const subscriber3 = jest.fn();
|
|
141
|
+
subject.subscribe(subscriber1);
|
|
142
|
+
// because the subject immediately calls the subscriber with the initial value
|
|
143
|
+
expect(() => subject.subscribe(subscriber2)).toThrowError('Something went wrong');
|
|
144
|
+
subscriber2.mockClear();
|
|
145
|
+
subject.subscribe(subscriber3);
|
|
146
|
+
// since ths subscriber throws an error, the subject should not call it
|
|
147
|
+
subject.publish('Hello'); // this should not call subscriber2 and should not throw an error
|
|
148
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
149
|
+
expect(subscriber3).toHaveBeenCalledWith('Hello');
|
|
150
|
+
expect(subscriber2).not.toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('EventSubject', () => {
|
|
154
|
+
it('should be defined', () => {
|
|
155
|
+
expect(pubSub_1.EventPubSub).toBeDefined();
|
|
156
|
+
});
|
|
157
|
+
it('should be a class', () => {
|
|
158
|
+
expect(pubSub_1.EventPubSub).toBeInstanceOf(Function);
|
|
159
|
+
});
|
|
160
|
+
// Functionality tests
|
|
161
|
+
it('should publish a message to all subscribers', () => {
|
|
162
|
+
const subject = new pubSub_1.EventPubSub();
|
|
163
|
+
const subscriber = jest.fn();
|
|
164
|
+
subject.subscribe('test', subscriber); // test with one subscriber
|
|
165
|
+
subject.publish('test', 'Hello');
|
|
166
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
167
|
+
});
|
|
168
|
+
it('should publish a message to all subscribers', () => {
|
|
169
|
+
const subject = new pubSub_1.EventPubSub();
|
|
170
|
+
const subscriber1 = jest.fn();
|
|
171
|
+
const subscriber2 = jest.fn();
|
|
172
|
+
subject.subscribe('test', subscriber1); // test with two subscribers
|
|
173
|
+
subject.subscribe('test', subscriber2);
|
|
174
|
+
subject.publish('test', 'Hello');
|
|
175
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
176
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello');
|
|
177
|
+
});
|
|
178
|
+
it('should publish a message to all subscribers', () => {
|
|
179
|
+
// including subscribers that subscribe after the first message is published
|
|
180
|
+
const subject = new pubSub_1.EventPubSub();
|
|
181
|
+
const subscriber1 = jest.fn();
|
|
182
|
+
const subscriber2 = jest.fn();
|
|
183
|
+
subject.subscribe('test', subscriber1);
|
|
184
|
+
subject.publish('test', 'Hello');
|
|
185
|
+
subject.subscribe('test', subscriber2);
|
|
186
|
+
subject.publish('test', 'Hello Again');
|
|
187
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
188
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello Again');
|
|
189
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello Again');
|
|
190
|
+
});
|
|
191
|
+
it('should not call a function if the event name does not match', () => {
|
|
192
|
+
const subject = new pubSub_1.EventPubSub();
|
|
193
|
+
const subscriber = jest.fn();
|
|
194
|
+
subject.subscribe('test', subscriber);
|
|
195
|
+
subject.publish('test2', 'Hello');
|
|
196
|
+
expect(subscriber).not.toHaveBeenCalled();
|
|
197
|
+
});
|
|
198
|
+
it('should not call a function if the event name does not match', () => {
|
|
199
|
+
// including subscribers that subscribe after the first message is published
|
|
200
|
+
const subject = new pubSub_1.EventPubSub();
|
|
201
|
+
const subscriber1 = jest.fn();
|
|
202
|
+
const subscriber2 = jest.fn();
|
|
203
|
+
subject.subscribe('test', subscriber1);
|
|
204
|
+
subject.publish('test', 'Hello');
|
|
205
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
206
|
+
expect(subscriber2).not.toHaveBeenCalled();
|
|
207
|
+
subscriber1.mockClear();
|
|
208
|
+
subscriber2.mockClear();
|
|
209
|
+
subject.subscribe('test2', subscriber2);
|
|
210
|
+
subject.publish('test2', 'Hello Again');
|
|
211
|
+
expect(subscriber1).not.toHaveBeenCalled();
|
|
212
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello Again');
|
|
213
|
+
});
|
|
214
|
+
it('should accept a generic subscriber', () => {
|
|
215
|
+
const subject = new pubSub_1.EventPubSub();
|
|
216
|
+
const subscriber = jest.fn();
|
|
217
|
+
subject.subscribeAll(subscriber);
|
|
218
|
+
subject.publish('test', 'Hello');
|
|
219
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
220
|
+
});
|
|
221
|
+
it('should accept a generic subscriber', () => {
|
|
222
|
+
const subject = new pubSub_1.EventPubSub();
|
|
223
|
+
const subscriber = jest.fn();
|
|
224
|
+
subject.subscribeAll(subscriber);
|
|
225
|
+
subject.publish('test', 'Hello');
|
|
226
|
+
subject.publish('test2', 'Hello Again');
|
|
227
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
228
|
+
expect(subscriber).toHaveBeenCalledWith('Hello Again');
|
|
229
|
+
});
|
|
230
|
+
it('should be able to unsubscribe from a specific event', () => {
|
|
231
|
+
const subject = new pubSub_1.EventPubSub();
|
|
232
|
+
const subscriber = jest.fn();
|
|
233
|
+
const sub = subject.subscribe('test', subscriber);
|
|
234
|
+
subject.publish('test', 'Hello');
|
|
235
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
236
|
+
subscriber.mockClear();
|
|
237
|
+
sub.unsubscribe();
|
|
238
|
+
subject.publish('test', 'Hello Again');
|
|
239
|
+
expect(subscriber).not.toHaveBeenCalledWith('Hello Again');
|
|
240
|
+
});
|
|
241
|
+
it('should complete the subscription when unsubscribed', () => {
|
|
242
|
+
const subject = new pubSub_1.EventPubSub();
|
|
243
|
+
const subscriber = jest.fn();
|
|
244
|
+
const subscriber2 = jest.fn();
|
|
245
|
+
const subscriber3 = jest.fn();
|
|
246
|
+
subject.subscribe('test', subscriber);
|
|
247
|
+
subject.subscribe('test1', subscriber2);
|
|
248
|
+
subject.subscribe('test2', subscriber3);
|
|
249
|
+
subject.publish('test', 'Hello');
|
|
250
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
251
|
+
subscriber.mockClear();
|
|
252
|
+
subject.publish('test1', 'Hello Again');
|
|
253
|
+
expect(subscriber).not.toHaveBeenCalledWith('Hello Again');
|
|
254
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello Again');
|
|
255
|
+
subscriber2.mockClear();
|
|
256
|
+
subject.publish('test2', 'Hello Again');
|
|
257
|
+
expect(subscriber).not.toHaveBeenCalledWith('Hello Again');
|
|
258
|
+
expect(subscriber2).not.toHaveBeenCalledWith('Hello Again');
|
|
259
|
+
expect(subscriber3).toHaveBeenCalledWith('Hello Again');
|
|
260
|
+
subscriber3.mockClear();
|
|
261
|
+
subject.complete(); // complete all subscriptions
|
|
262
|
+
subject.publish('test', 'Hello Again');
|
|
263
|
+
expect(subscriber).not.toHaveBeenCalledWith('Hello Again');
|
|
264
|
+
subject.publish('test1', 'Hello Again');
|
|
265
|
+
expect(subscriber2).not.toHaveBeenCalledWith('Hello Again');
|
|
266
|
+
subject.publish('test2', 'Hello Again');
|
|
267
|
+
expect(subscriber3).not.toHaveBeenCalledWith('Hello Again');
|
|
268
|
+
});
|
|
269
|
+
it('should throw an error if one of its subscribers throw an error', () => {
|
|
270
|
+
const subject = new pubSub_1.EventPubSub();
|
|
271
|
+
const subscriber1 = jest.fn();
|
|
272
|
+
const subscriber2 = jest.fn(() => {
|
|
273
|
+
throw new Error('Something went wrong');
|
|
274
|
+
});
|
|
275
|
+
const subscriber3 = jest.fn();
|
|
276
|
+
subject.subscribeAll(subscriber1);
|
|
277
|
+
subject.subscribeAll(subscriber2);
|
|
278
|
+
subject.subscribe('event', subscriber3);
|
|
279
|
+
expect(() => subject.publish('event', 'Hello')).toThrowError('Something went wrong');
|
|
280
|
+
expect(subscriber1).toHaveBeenCalledWith('Hello');
|
|
281
|
+
expect(subscriber2).toHaveBeenCalledWith('Hello');
|
|
282
|
+
expect(subscriber3).not.toHaveBeenCalled();
|
|
283
|
+
});
|
|
284
|
+
it('should be possible to unsubscribe from a generic subscriber', () => {
|
|
285
|
+
const subject = new pubSub_1.EventPubSub();
|
|
286
|
+
const subscriber = jest.fn();
|
|
287
|
+
const sub = subject.subscribeAll(subscriber);
|
|
288
|
+
subject.publish('test', 'Hello');
|
|
289
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
290
|
+
subscriber.mockClear();
|
|
291
|
+
sub.unsubscribe();
|
|
292
|
+
subject.publish('test', 'Hello Again');
|
|
293
|
+
expect(subscriber).not.toHaveBeenCalledWith('Hello Again');
|
|
294
|
+
});
|
|
295
|
+
it('should be able to add an oncomplete callback', () => {
|
|
296
|
+
const subject = new pubSub_1.EventPubSub();
|
|
297
|
+
const subscriber = jest.fn();
|
|
298
|
+
const subscriber2 = jest.fn();
|
|
299
|
+
subject.onComplete(subscriber2);
|
|
300
|
+
subject.subscribe('test', subscriber);
|
|
301
|
+
subject.publish('test', 'Hello');
|
|
302
|
+
expect(subscriber).toHaveBeenCalledWith('Hello');
|
|
303
|
+
subscriber.mockClear();
|
|
304
|
+
subject.complete();
|
|
305
|
+
expect(subscriber2).toHaveBeenCalled();
|
|
306
|
+
subject.publish('test', 'Hello Again');
|
|
307
|
+
expect(subscriber).not.toHaveBeenCalledWith('Hello Again');
|
|
308
|
+
});
|
|
309
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
export declare class PondDocument<T> {
|
|
2
|
+
private readonly _id;
|
|
3
|
+
private readonly _getDoc;
|
|
4
|
+
private readonly _removeDoc;
|
|
5
|
+
private readonly _updateDoc;
|
|
6
|
+
|
|
7
|
+
constructor(id: string, removeDoc: () => void, updateDoc: (value: T) => PondDocument<T>, getDoc: () => T);
|
|
8
|
+
|
|
9
|
+
get id(): string;
|
|
10
|
+
|
|
11
|
+
get doc(): T;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @desc Removes the document from the collection
|
|
15
|
+
*/
|
|
16
|
+
removeDoc(): T;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @desc Updates the document in the collection
|
|
20
|
+
* @param value - the new value of the document
|
|
21
|
+
*/
|
|
22
|
+
updateDoc(value: T): this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
declare type UpdateCallback<T> = (data: {
|
|
26
|
+
oldValue: T | null; currentValue: T | null;
|
|
27
|
+
}) => void;
|
|
28
|
+
|
|
29
|
+
export declare class SimpleBase<T> {
|
|
30
|
+
constructor(callbacks?: UpdateCallback<T>);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @desc Get the number of documents
|
|
34
|
+
*/
|
|
35
|
+
get size(): number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @desc Get all the documents in the database
|
|
39
|
+
*/
|
|
40
|
+
get all(): PondDocument<T>[];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @desc Gets all the keys of the database
|
|
44
|
+
*/
|
|
45
|
+
get keys(): string[];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @desc Gets all the values of the database
|
|
49
|
+
*/
|
|
50
|
+
get values(): T[];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @desc Makes the database iterable
|
|
54
|
+
*/
|
|
55
|
+
[Symbol.iterator](): IterableIterator<PondDocument<T>>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @desc Create a generator for the pond
|
|
59
|
+
*/
|
|
60
|
+
generator(): Generator<PondDocument<T>>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @desc Get a document by key
|
|
64
|
+
* @param key - The key of the document
|
|
65
|
+
*/
|
|
66
|
+
get(key: string): PondDocument<T> | null;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @desc getOrCreate a document in the database
|
|
70
|
+
* @param key - The key of the document
|
|
71
|
+
* @param creator - The function to create the document
|
|
72
|
+
*/
|
|
73
|
+
getOrCreate(key: string, creator: (doc: Readonly<PondDocument<T>>) => T): PondDocument<T>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @desc Upsert a document in the database
|
|
77
|
+
* @param key - The key of the document
|
|
78
|
+
* @param value - The value of the document
|
|
79
|
+
*/
|
|
80
|
+
upsert(key: string, value: T): PondDocument<T>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @desc checks if a document exists
|
|
84
|
+
* @param key - The key of the document
|
|
85
|
+
*/
|
|
86
|
+
has(key: string): boolean;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @desc Set a document to the database
|
|
90
|
+
* @param key - The key of the document
|
|
91
|
+
* @param value - The value of the document
|
|
92
|
+
*/
|
|
93
|
+
set(key: string, value: T): PondDocument<T>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @desc Find a document by a query function
|
|
97
|
+
* @param query - The query function
|
|
98
|
+
*/
|
|
99
|
+
find(query: (doc: T, id: string) => boolean): PondDocument<T> | null;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @desc Map the pond to a new array
|
|
103
|
+
* @param mapper - The mapper function
|
|
104
|
+
*/
|
|
105
|
+
map<U>(mapper: (doc: T, id: string) => U): U[];
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @desc Filters the pond using a query function
|
|
109
|
+
* @param query - The query function
|
|
110
|
+
*/
|
|
111
|
+
filter(query: (doc: T, id: string) => boolean): PondDocument<T>[];
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @desc Reduce the pond to a single value
|
|
115
|
+
* @param reducer - The reducer function
|
|
116
|
+
* @param initialValue - The initial value of the reducer
|
|
117
|
+
*/
|
|
118
|
+
reduce<U>(reducer: (accumulator: U, currentValue: T) => U, initialValue: U): U;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @desc Generate a generic pond document
|
|
122
|
+
* @param id - The id of the document
|
|
123
|
+
*/
|
|
124
|
+
createGenericDocument(id?: string): PondDocument<T>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @desc Gets the raw database
|
|
128
|
+
* @protected
|
|
129
|
+
*/
|
|
130
|
+
protected _getDB(): Record<string, T>;
|
|
131
|
+
}
|