Skip to content

Commit df02262

Browse files
committed
enhance middleware support by adding wildcard method
1 parent 5fd1509 commit df02262

File tree

4 files changed

+70
-18
lines changed

4 files changed

+70
-18
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,19 @@ await User.findByIdAndDelete(newUser._id);
9191

9292
### Middleware
9393

94-
Register middleware for operations:
94+
Register middleware for operations (wildcard `*` is supported only for method):
9595

9696
```js
97-
User.pre('create', async (doc) => {
98-
// Before creating user
97+
User.pre('*', async (doc) => {
98+
// Before any operation
9999
});
100100

101101
User.post('update', async (doc) => {
102102
// After updating user
103103
});
104104
```
105105

106-
Supported methods: `'create' | 'read' | 'update' | 'replace' | 'delete'`.
106+
Supported methods: `'create' | 'read' | 'update' | 'replace' | 'delete' | '*'`.
107107

108108
### Querying
109109

src/lib/middleware.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@ const middlewares = new Map();
66
const allowedTypes = ['pre', 'post'];
77
const allowedMethods = ['create', 'read', 'update', 'replace', 'delete'];
88

9+
const isAllowedType = (val) => allowedTypes.includes(val);
10+
const isAllowedMethod = (val) => val === '*' || allowedMethods.includes(val);
11+
912
const registerMiddleware = (type, collection, method, fn) => {
1013
if (getType(method) === 'array') {
1114
return method.map((el) => registerMiddleware(type, collection, el, fn));
1215
}
1316

14-
if (!allowedTypes.includes(type)) {
17+
if (!isAllowedType(type)) {
1518
throw new Error(`Invalid middleware type: ${type}`);
1619
}
1720

18-
if (getType(collection) !== 'string') {
21+
if (getType(collection) !== 'string' || collection === '*') {
1922
throw new Error(`Invalid middleware collection: ${collection}`);
2023
}
2124

22-
if (getType(method) !== 'string' || !allowedMethods.includes(method)) {
25+
if (!isAllowedMethod(method)) {
2326
throw new Error(`Invalid middleware method: ${method}`);
2427
}
2528

@@ -42,9 +45,9 @@ const unregisterMiddleware = (id) => {
4245

4346
const executeOneMiddleware = async (type, collection, method, res) => {
4447
const results = [];
45-
for (const middleware of middlewares.values()) {
46-
if (middleware.type === type && middleware.collection === collection && middleware.method === method) {
47-
results.push(middleware);
48+
for (const mw of middlewares.values()) {
49+
if (mw.type === type && mw.collection === collection && (mw.method === '*' || mw.method === method)) {
50+
results.push(mw);
4851
}
4952
}
5053

src/stormflow.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,16 @@ export type MiddlewareFunction = (item: any) => Promise<void>;
7474
export interface StormFlowModel {
7575
/**
7676
* Register a middleware function to run before the specified action.
77-
* @param method One of 'create', 'read', 'update', 'replace', 'delete'
77+
* @param method One of 'create', 'read', 'update', 'replace', 'delete' vagy '*'
7878
* @param fn Middleware function to execute
7979
*/
80-
pre(method: 'create' | 'read' | 'update' | 'replace' | 'delete', fn: MiddlewareFunction): void;
80+
pre(method: 'create' | 'read' | 'update' | 'replace' | 'delete' | '*', fn: MiddlewareFunction): void;
8181
/**
8282
* Register a middleware function to run after the specified action.
83-
* @param method One of 'create' | 'read' | 'update' | 'replace' | 'delete'
83+
* @param method One of 'create', 'read' | 'update' | 'replace' | 'delete' vagy '*'
8484
* @param fn Middleware function to execute
8585
*/
86-
post(method: 'create' | 'read' | 'update' | 'replace' | 'delete', fn: MiddlewareFunction): void;
86+
post(method: 'create' | 'read' | 'update' | 'replace' | 'delete' | '*', fn: MiddlewareFunction): void;
8787
/** Inserts a single document */
8888
insertOne(item: any): Promise<any>;
8989
/** Inserts multiple documents */

test/lib/middleware.test.js

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ describe('Middleware module', () => {
2727

2828
it('registers successfully with valid inputs', () => {
2929
const id = registerMiddleware('pre', 'products', 'create', () => {});
30+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
31+
globalThis.__registeredMiddlewareIds.push(id);
3032
expect(typeof id).toBe('string');
3133
});
3234

3335
it('registers multiple middleware if method is an array', () => {
3436
const ids = registerMiddleware('post', 'orders', ['create', 'update'], () => {});
37+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
38+
globalThis.__registeredMiddlewareIds.push(...ids);
3539
expect(Array.isArray(ids)).toBe(true);
3640
expect(ids.length).toBe(2);
3741
ids.forEach((id) => expect(typeof id).toBe('string'));
@@ -45,6 +49,8 @@ describe('Middleware module', () => {
4549

4650
it('removes existing middleware and returns true', () => {
4751
const id = registerMiddleware('pre', 'products', 'create', () => {});
52+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
53+
globalThis.__registeredMiddlewareIds.push(id);
4854
expect(unregisterMiddleware(id)).toBe(true);
4955
});
5056

@@ -56,7 +62,9 @@ describe('Middleware module', () => {
5662
describe('executeMiddleware', () => {
5763
it('calls middleware callback once', async () => {
5864
const fn = jest.fn();
59-
registerMiddleware('pre', 'products', 'create', fn);
65+
const id = registerMiddleware('pre', 'products', 'create', fn);
66+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
67+
globalThis.__registeredMiddlewareIds.push(id);
6068
const res = {};
6169
await executeMiddleware('pre', 'products', 'create', res);
6270
expect(fn).toHaveBeenCalledTimes(1);
@@ -65,7 +73,9 @@ describe('Middleware module', () => {
6573

6674
it('calls middleware multiple times if method array and multiple res', async () => {
6775
const fn = jest.fn();
68-
registerMiddleware('pre', 'products', ['create', 'update'], fn);
76+
const ids = registerMiddleware('pre', 'products', ['create', 'update'], fn);
77+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
78+
globalThis.__registeredMiddlewareIds.push(...ids);
6979
const resArray = [{}, {}];
7080
await executeMiddleware('pre', 'products', 'create', resArray);
7181
await executeMiddleware('pre', 'products', 'update', resArray);
@@ -74,7 +84,9 @@ describe('Middleware module', () => {
7484

7585
it('does not call middleware if type or method does not match', async () => {
7686
const fn = jest.fn();
77-
registerMiddleware('pre', 'products', 'create', fn);
87+
const id = registerMiddleware('pre', 'products', 'create', fn);
88+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
89+
globalThis.__registeredMiddlewareIds.push(id);
7890
await executeMiddleware('post', 'products', 'create', {});
7991
expect(fn).not.toHaveBeenCalled();
8092
});
@@ -83,9 +95,46 @@ describe('Middleware module', () => {
8395
const errorFn = jest.fn(async () => {
8496
throw new Error('fail');
8597
});
86-
registerMiddleware('pre', 'products', 'create', errorFn);
98+
const id = registerMiddleware('pre', 'products', 'create', errorFn);
99+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
100+
globalThis.__registeredMiddlewareIds.push(id);
87101
await expect(executeMiddleware('pre', 'products', 'create', {})).rejects.toThrow('fail');
88102
expect(errorFn).toHaveBeenCalledTimes(1);
89103
});
90104
});
105+
106+
describe('wildcard middleware', () => {
107+
it('calls middleware for any method when method is *', async () => {
108+
const fn = jest.fn();
109+
const id = registerMiddleware('pre', 'products', '*', fn);
110+
globalThis.__registeredMiddlewareIds = globalThis.__registeredMiddlewareIds || [];
111+
globalThis.__registeredMiddlewareIds.push(id);
112+
await executeMiddleware('pre', 'products', 'create', {});
113+
await executeMiddleware('pre', 'products', 'update', {});
114+
expect(fn).toHaveBeenCalledTimes(2);
115+
});
116+
117+
it('does not call middleware for type wildcard', async () => {
118+
const fn = jest.fn();
119+
// type wildcard nem támogatott
120+
expect(() => registerMiddleware('*', 'products', 'create', fn)).toThrow('Invalid middleware type: *');
121+
});
122+
123+
it('does not call middleware for collection wildcard', async () => {
124+
const fn = jest.fn();
125+
// collection wildcard nem támogatott
126+
expect(() => registerMiddleware('pre', '*', 'create', fn)).toThrow('Invalid middleware collection: *');
127+
});
128+
});
129+
130+
afterEach(() => {
131+
// Az összes regisztrált middleware eltávolítása
132+
// A registerMiddleware visszatérési értéke lehet string vagy tömb
133+
if (globalThis.__registeredMiddlewareIds) {
134+
for (const id of globalThis.__registeredMiddlewareIds) {
135+
unregisterMiddleware(id);
136+
}
137+
globalThis.__registeredMiddlewareIds = [];
138+
}
139+
});
91140
});

0 commit comments

Comments
 (0)