Skip to content

Commit 5ad39ca

Browse files
committed
[middleware] Module skeleton
1 parent 72132c8 commit 5ad39ca

9 files changed

Lines changed: 215 additions & 1 deletion

File tree

gulpfile.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const ALL_MODULES = [
2020
'indexes',
2121
'mergeable-store',
2222
'metrics',
23+
'middleware',
2324
'persisters',
2425
'persisters/persister-automerge',
2526
'persisters/persister-browser',

src/@types/middleware/docs.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* The middleware module of the TinyBase project provides the ability to
3+
* intercept and validate incoming writes to Store objects.
4+
*
5+
* The main entry point to this module is the createMiddleware function, which
6+
* returns a new Middleware object. From there, you can register hooks that are
7+
* called before data is written to the Store.
8+
* @packageDocumentation
9+
* @module middleware
10+
* @since v8.0.0
11+
*/
12+
/// middleware
13+
/**
14+
* A Middleware object lets you intercept and validate writes to a Store.
15+
*
16+
* This is useful for enforcing business rules, data validation, or
17+
* transformation logic before data is persisted in the Store.
18+
*
19+
* Create a Middleware object easily with the createMiddleware function.
20+
* @example
21+
* This example shows a very simple lifecycle of a Middleware object: from
22+
* creation, to getting the Store reference, and then destroying it.
23+
*
24+
* ```js
25+
* import {createMiddleware, createStore} from 'tinybase';
26+
*
27+
* const store = createStore();
28+
* const middleware = createMiddleware(store);
29+
*
30+
* console.log(middleware.getStore() == store);
31+
* // -> true
32+
*
33+
* middleware.destroy();
34+
* ```
35+
* @category Middleware
36+
* @since v8.0.0
37+
*/
38+
/// Middleware
39+
{
40+
/**
41+
* The getStore method returns a reference to the underlying Store that is
42+
* backing this Middleware object.
43+
* @returns A reference to the Store.
44+
* @example
45+
* This example creates a Middleware object against a newly-created Store and
46+
* then gets its reference in order to update its data.
47+
*
48+
* ```js
49+
* import {createMiddleware, createStore} from 'tinybase';
50+
*
51+
* const middleware = createMiddleware(createStore());
52+
* console.log(middleware.getStore().getTables());
53+
* // -> {}
54+
* middleware.destroy();
55+
* ```
56+
* @category Getter
57+
* @since v8.0.0
58+
*/
59+
/// Middleware.getStore
60+
/**
61+
* The destroy method should be called when this Middleware object is no
62+
* longer used. It removes all hooks and listeners from the Store, and
63+
* unregisters the Middleware from the Store.
64+
* @example
65+
* This example creates a Middleware object against a newly-created Store and
66+
* then destroys it.
67+
*
68+
* ```js
69+
* import {createMiddleware, createStore} from 'tinybase';
70+
*
71+
* const store = createStore();
72+
* const middleware = createMiddleware(store);
73+
* middleware.destroy();
74+
* ```
75+
* @category Lifecycle
76+
* @since v8.0.0
77+
*/
78+
/// Middleware.destroy
79+
}
80+
/**
81+
* The createMiddleware function creates a Middleware object, and is the main
82+
* entry point into the middleware module.
83+
*
84+
* A given Store can only have one Middleware object associated with it. If you
85+
* call this function twice on the same Store, your second call will return a
86+
* reference to the Middleware object created by the first.
87+
* @param store The Store for which to register the Middleware.
88+
* @returns A reference to the new Middleware object.
89+
* @example
90+
* This example creates a Middleware object.
91+
*
92+
* ```js
93+
* import {createMiddleware, createStore} from 'tinybase';
94+
*
95+
* const store = createStore();
96+
* const middleware = createMiddleware(store);
97+
* console.log(middleware.getStore() == store);
98+
* // -> true
99+
* middleware.destroy();
100+
* ```
101+
* @example
102+
* This example creates a Middleware object, and calls the method a second time
103+
* for the same Store to return the same object.
104+
*
105+
* ```js
106+
* import {createMiddleware, createStore} from 'tinybase';
107+
*
108+
* const store = createStore();
109+
* const middleware = createMiddleware(store);
110+
* console.log(middleware === createMiddleware(store));
111+
* // -> true
112+
* middleware.destroy();
113+
* ```
114+
* @category Creation
115+
* @since v8.0.0
116+
*/
117+
/// createMiddleware

src/@types/middleware/index.d.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// middleware
2+
import type {Store} from '../store/index.d.ts';
3+
4+
/// Middleware
5+
export interface Middleware {
6+
/// Middleware.getStore
7+
getStore(): Store;
8+
9+
/// Middleware.destroy
10+
destroy(): void;
11+
}
12+
13+
/// createMiddleware
14+
export function createMiddleware(store: Store): Middleware;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// middleware
2+
import type {
3+
OptionalSchemas,
4+
Store,
5+
} from '../../store/with-schemas/index.d.ts';
6+
7+
/// Middleware
8+
export interface Middleware<in out Schemas extends OptionalSchemas> {
9+
/// Middleware.getStore
10+
getStore(): Store<Schemas>;
11+
12+
/// Middleware.destroy
13+
destroy(): void;
14+
}
15+
16+
/// createMiddleware
17+
export function createMiddleware<Schemas extends OptionalSchemas>(
18+
store: Store<Schemas>,
19+
): Middleware<Schemas>;

src/common/definable.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {Checkpoints} from '../@types/checkpoints/index.d.ts';
22
import type {Id, Ids, SortKey} from '../@types/common/index.d.ts';
33
import type {Indexes} from '../@types/indexes/index.d.ts';
44
import type {Metrics} from '../@types/metrics/index.d.ts';
5+
import type {Middleware} from '../@types/middleware/index.d.ts';
56
import type {Queries} from '../@types/queries/index.d.ts';
67
import type {Relationships} from '../@types/relationships/index.d.ts';
78
import type {Cell, GetCell, Store} from '../@types/store/index.d.ts';
@@ -255,7 +256,13 @@ export const getRowCellFunction = <RowValue>(
255256
((): RowValue => defaultCellValue ?? (EMPTY_STRING as any as RowValue)));
256257

257258
export const getCreateFunction = <
258-
Thing extends Metrics | Indexes | Relationships | Checkpoints | Queries,
259+
Thing extends
260+
| Metrics
261+
| Middleware
262+
| Indexes
263+
| Relationships
264+
| Checkpoints
265+
| Queries,
259266
>(
260267
getFunction: (store: Store) => Thing,
261268
initFunction?: (thing: Thing) => void,

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './common/index.ts';
33
export * from './indexes/index.ts';
44
export * from './mergeable-store/index.ts';
55
export * from './metrics/index.ts';
6+
export * from './middleware/index.ts';
67
export * from './queries/index.ts';
78
export * from './relationships/index.ts';
89
export * from './store/index.ts';

src/middleware/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type {
2+
Middleware,
3+
createMiddleware as createMiddlewareDecl,
4+
} from '../@types/middleware/index.d.ts';
5+
import type {Store} from '../@types/store/index.d.ts';
6+
import {getCreateFunction} from '../common/definable.ts';
7+
import {objFreeze} from '../common/obj.ts';
8+
9+
export const createMiddleware = getCreateFunction(
10+
(store: Store): Middleware => {
11+
const getStore = (): Store => store;
12+
13+
const destroy = (): void => {};
14+
15+
const middleware: any = {
16+
getStore,
17+
destroy,
18+
};
19+
20+
return objFreeze(middleware as Middleware);
21+
},
22+
) as typeof createMiddlewareDecl;

src/tsconfig.tsbuildinfo

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {beforeEach, describe, expect, test} from 'vitest';
2+
3+
import type {Middleware, Store} from 'tinybase';
4+
import {createMiddleware, createStore} from 'tinybase';
5+
6+
let store: Store;
7+
let middleware: Middleware;
8+
9+
beforeEach(() => {
10+
store = createStore();
11+
middleware = createMiddleware(store);
12+
});
13+
14+
describe('Creates', () => {
15+
test('basic', () => {
16+
expect(middleware).toBeDefined();
17+
});
18+
19+
test('getStore', () => {
20+
expect(middleware.getStore()).toBe(store);
21+
});
22+
23+
test('same middleware for same store', () => {
24+
expect(createMiddleware(store)).toBe(middleware);
25+
});
26+
});
27+
28+
describe('Destroys', () => {
29+
test('basic', () => {
30+
middleware.destroy();
31+
});
32+
});

0 commit comments

Comments
 (0)