@aiao/rxdb-react 0.0.7

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aiao Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # rxdb-react
@@ -0,0 +1,163 @@
1
+ import { EntityStaticType, EntityType } from '../../rxdb/src/index.ts';
2
+ type UseOptions<T> = T | (() => T);
3
+ export interface RxDBResource<T> {
4
+ /**
5
+ * 资源的数值
6
+ */
7
+ readonly value: T;
8
+ /**
9
+ * 资源的错误
10
+ */
11
+ readonly error: Error | undefined;
12
+ /**
13
+ * 资源的加载状态
14
+ */
15
+ readonly isLoading: boolean;
16
+ /**
17
+ * 资源的空状态
18
+ */
19
+ readonly isEmpty: boolean | undefined;
20
+ /**
21
+ * 资源是否具有数值
22
+ */
23
+ readonly hasValue: boolean;
24
+ }
25
+ /**
26
+ * 通过 ID 获取单个实体
27
+ *
28
+ * @param EntityType 实体类
29
+ * @param options 实体的 ID 或选项对象
30
+ * @returns 包含实体、加载状态和错误的资源对象
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const { value: user, isLoading } = useGet(User, 'user-1');
35
+ * ```
36
+ */
37
+ export declare const useGet: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "getOptions">>) => RxDBResource<InstanceType<T> | undefined>;
38
+ /**
39
+ * Find one entity matching the criteria
40
+ *
41
+ * @param EntityType The entity class
42
+ * @param options Query options (where clause, sort, etc.)
43
+ * @returns A resource object containing the entity
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const { value: user } = useFindOne(User, { where: { name: 'Alice' } });
48
+ * ```
49
+ */
50
+ export declare const useFindOne: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findOneOptions">>) => RxDBResource<InstanceType<T> | undefined>;
51
+ /**
52
+ * Find one entity or throw an error if not found
53
+ *
54
+ * @param EntityType The entity class
55
+ * @param options Query options
56
+ * @returns A resource object containing the entity
57
+ */
58
+ export declare const useFindOneOrFail: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findOneOrFailOptions">>) => RxDBResource<InstanceType<T> | undefined>;
59
+ /**
60
+ * Find multiple entities matching the criteria
61
+ *
62
+ * @param EntityType The entity class
63
+ * @param options Query options
64
+ * @returns A resource object containing an array of entities
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const { value: users } = useFind(User, { where: { age: { $gt: 18 } } });
69
+ * ```
70
+ */
71
+ export declare const useFind: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findOptions">>) => RxDBResource<InstanceType<T>[]>;
72
+ /**
73
+ * Find all entities
74
+ *
75
+ * @param EntityType The entity class
76
+ * @param options Query options
77
+ * @returns A resource object containing all entities
78
+ */
79
+ export declare const useFindAll: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findAllOptions">>) => RxDBResource<InstanceType<T>[]>;
80
+ /**
81
+ * Count entities matching the criteria
82
+ *
83
+ * @param EntityType The entity class
84
+ * @param options Query options
85
+ * @returns A resource object containing the count
86
+ */
87
+ export declare const useCount: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "countOptions">>) => RxDBResource<number>;
88
+ /**
89
+ * Find all descendant entities in a tree structure
90
+ *
91
+ * @param EntityType The entity class
92
+ * @param options Tree query options (entityId, depth, etc.)
93
+ * @returns A resource object containing descendant entities
94
+ */
95
+ export declare const useFindDescendants: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<InstanceType<T>[]>;
96
+ /**
97
+ * Count descendant entities in a tree structure
98
+ *
99
+ * @param EntityType The entity class
100
+ * @param options Tree query options
101
+ * @returns A resource object containing the count
102
+ */
103
+ export declare const useCountDescendants: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<number>;
104
+ /**
105
+ * Find all ancestor entities in a tree structure
106
+ *
107
+ * @param EntityType The entity class
108
+ * @param options Tree query options
109
+ * @returns A resource object containing ancestor entities
110
+ */
111
+ export declare const useFindAncestors: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<InstanceType<T>[]>;
112
+ /**
113
+ * Count ancestor entities in a tree structure
114
+ *
115
+ * @param EntityType The entity class
116
+ * @param options Tree query options
117
+ * @returns A resource object containing the count
118
+ */
119
+ export declare const useCountAncestors: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<number>;
120
+ /**
121
+ * Find neighbor entities in a graph structure
122
+ *
123
+ * @param EntityType The entity class
124
+ * @param options Graph query options (entityId, direction, level, etc.)
125
+ * @returns A resource object containing neighbor entities
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * const { value: friends } = useGraphNeighbors(User, {
130
+ * entityId: 'user-1',
131
+ * direction: 'out',
132
+ * level: 1
133
+ * });
134
+ * ```
135
+ */
136
+ export declare const useGraphNeighbors: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findNeighborsOptions">>) => RxDBResource<InstanceType<T>[]>;
137
+ /**
138
+ * Count neighbor entities in a graph structure
139
+ *
140
+ * @param EntityType The entity class
141
+ * @param options Graph query options
142
+ * @returns A resource object containing the count
143
+ */
144
+ export declare const useCountNeighbors: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findNeighborsOptions">>) => RxDBResource<number>;
145
+ /**
146
+ * Find paths between two entities in a graph
147
+ *
148
+ * @param EntityType The entity class
149
+ * @param options Path query options (fromId, toId, maxDepth, etc.)
150
+ * @returns A resource object containing paths
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const { value: paths } = useGraphPaths(User, {
155
+ * fromId: 'user-1',
156
+ * toId: 'user-2',
157
+ * maxDepth: 5
158
+ * });
159
+ * ```
160
+ */
161
+ export declare const useGraphPaths: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findPathsOptions">>) => RxDBResource<any[]>;
162
+ export {};
163
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './hooks';
2
+ export * from './rxdb-react';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ import { isFunction as m } from "@aiao/utils";
2
+ import { useState as i, useRef as h, useMemo as F, useEffect as A, createContext as B, useContext as E } from "react";
3
+ import { jsx as O } from "react/jsx-runtime";
4
+ const s = (r, e, o, c) => {
5
+ const [D, R] = i(o), [b, d] = i(void 0), [g, f] = i(!0), [p, l] = i(void 0), [y, v] = i(!1), t = h(void 0), u = h(!0), x = F(() => m(c) ? c() : c, [c]);
6
+ return A(() => {
7
+ u.current = !0, t.current && (t.current.unsubscribe(), t.current = void 0);
8
+ const a = r[e];
9
+ if (!a || typeof a != "function") {
10
+ const n = new Error(`Method "${String(e)}" not found on EntityType`);
11
+ Promise.resolve().then(() => {
12
+ u.current && (d(n), f(!1));
13
+ });
14
+ return;
15
+ }
16
+ try {
17
+ t.current = a(x).subscribe({
18
+ next: (n) => {
19
+ u.current && (f(!1), v(!0), d(void 0), Array.isArray(n) ? l(n.length === 0) : l(n == null), R(n));
20
+ },
21
+ error: (n) => {
22
+ u.current && (f(!1), v(!1), d(n), console.error(`RxDB query error in ${String(e)}:`, n));
23
+ }
24
+ });
25
+ } catch (n) {
26
+ const P = n instanceof Error ? n : new Error(String(n));
27
+ Promise.resolve().then(() => {
28
+ u.current && (f(!1), d(P));
29
+ });
30
+ }
31
+ return () => {
32
+ u.current = !1, t.current && (t.current.unsubscribe(), t.current = void 0);
33
+ };
34
+ }, [r, e, x]), {
35
+ value: D,
36
+ error: b,
37
+ isLoading: g,
38
+ isEmpty: p,
39
+ hasValue: y
40
+ };
41
+ }, S = (r, e) => s(r, "get", void 0, e), G = (r, e) => s(r, "findOne", void 0, e), V = (r, e) => s(r, "findOneOrFail", void 0, e), q = (r, e) => s(r, "find", [], e), I = (r, e) => s(r, "findAll", [], e), L = (r, e) => s(r, "count", 0, e), $ = (r, e) => s(r, "findDescendants", [], e), j = (r, e) => s(r, "countDescendants", 0, e), k = (r, e) => s(r, "findAncestors", [], e), H = (r, e) => s(r, "countAncestors", 0, e), Q = (r, e) => s(r, "findNeighbors", [], e), z = (r, e) => s(r, "countNeighbors", 0, e), J = (r, e) => s(r, "findPaths", [], e);
42
+ function C() {
43
+ const r = B(void 0);
44
+ return {
45
+ useRxDB: ((e) => {
46
+ const o = E(r);
47
+ if (e !== void 0) return e;
48
+ if (!o) throw new Error("No RxDB instance found, use RxDBProvider to provide one");
49
+ return o;
50
+ }),
51
+ RxDBProvider: ({ children: e, db: o }) => /* @__PURE__ */ O(r.Provider, { value: o, children: e })
52
+ };
53
+ }
54
+ const { RxDBProvider: K, useRxDB: T } = C();
55
+ export {
56
+ K as RxDBProvider,
57
+ C as makeRxDBProvider,
58
+ L as useCount,
59
+ H as useCountAncestors,
60
+ j as useCountDescendants,
61
+ z as useCountNeighbors,
62
+ q as useFind,
63
+ I as useFindAll,
64
+ k as useFindAncestors,
65
+ $ as useFindDescendants,
66
+ G as useFindOne,
67
+ V as useFindOneOrFail,
68
+ S as useGet,
69
+ Q as useGraphNeighbors,
70
+ J as useGraphPaths,
71
+ T as useRxDB
72
+ };
@@ -0,0 +1,19 @@
1
+ import { RxDB } from '../../rxdb/src/index.ts';
2
+ import { default as React } from 'react';
3
+ interface Props<T extends RxDB> {
4
+ children?: React.ReactNode;
5
+ db?: T;
6
+ }
7
+ type RxDBProviderType<T extends RxDB> = (props: Props<T>) => React.JSX.Element;
8
+ type UseRxDB<T extends RxDB> = (db?: T) => T;
9
+ interface RxDBProviderSet<T extends RxDB> {
10
+ RxDBProvider: RxDBProviderType<T>;
11
+ useRxDB: UseRxDB<T>;
12
+ }
13
+ /**
14
+ * RxDB 依赖注入
15
+ */
16
+ declare function makeRxDBProvider<T extends RxDB>(): RxDBProviderSet<T>;
17
+ declare const RxDBProvider: RxDBProviderType<RxDB>, useRxDB: UseRxDB<RxDB>;
18
+ export { makeRxDBProvider, RxDBProvider, useRxDB };
19
+ //# sourceMappingURL=rxdb-react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rxdb-react.d.ts","sourceRoot":"","sources":["../src/rxdb-react.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,KAAoC,MAAM,OAAO,CAAC;AAEzD,UAAU,KAAK,CAAC,CAAC,SAAS,IAAI;IAC5B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,EAAE,CAAC,EAAE,CAAC,CAAC;CACR;AAED,KAAK,gBAAgB,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AAC/E,KAAK,OAAO,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAE7C,UAAU,eAAe,CAAC,CAAC,SAAS,IAAI;IACtC,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CACrB;AAED;;GAEG;AACH,iBAAS,gBAAgB,CAAC,CAAC,SAAS,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,CAc9D;AAED,QAAA,MAAQ,YAAY,0BAAE,OAAO,eAA6B,CAAC;AAE3D,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import nx from '@nx/eslint-plugin';
2
+ import baseConfig from '../../eslint.config.mjs';
3
+
4
+ export default [
5
+ ...baseConfig,
6
+ ...nx.configs['flat/react'],
7
+ {
8
+ files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
9
+ // Override or add rules here
10
+ rules: {}
11
+ }
12
+ ];
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@aiao/rxdb-react",
3
+ "version": "0.0.7",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "@aiao/source": "./src/index.ts",
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "@aiao/rxdb": "0.0.7",
19
+ "@aiao/utils": "0.0.7"
20
+ },
21
+ "nx": {
22
+ "name": "rxdb-react",
23
+ "tags": [
24
+ "react-lib"
25
+ ]
26
+ }
27
+ }
@@ -0,0 +1,127 @@
1
+ import { of } from 'rxjs';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { useFind, useFindOne, useGet } from './hooks';
4
+
5
+ // Mock React hooks
6
+ let mockState: any[] = [];
7
+ let mockStateIndex = 0;
8
+ let mockEffectCleanups: Array<() => void> = [];
9
+
10
+ vi.mock('react', () => ({
11
+ useState: (initial: any) => {
12
+ const index = mockStateIndex++;
13
+ if (mockState[index] === undefined) {
14
+ mockState[index] = initial;
15
+ }
16
+ const setState = (newValue: any) => {
17
+ mockState[index] = typeof newValue === 'function' ? newValue(mockState[index]) : newValue;
18
+ };
19
+ return [mockState[index], setState];
20
+ },
21
+ useEffect: (effect: () => any) => {
22
+ const cleanup = effect();
23
+ if (cleanup) mockEffectCleanups.push(cleanup);
24
+ },
25
+ useRef: (initial: any) => ({ current: initial }),
26
+ useMemo: (fn: () => any, deps: any[]) => fn()
27
+ }));
28
+
29
+ // Mock entity type
30
+ class MockEntity {
31
+ id!: string;
32
+ name!: string;
33
+ static get = vi.fn();
34
+ static findOne = vi.fn();
35
+ static find = vi.fn();
36
+ }
37
+
38
+ describe('useGet', () => {
39
+ beforeEach(() => {
40
+ vi.clearAllMocks();
41
+ mockState = [];
42
+ mockStateIndex = 0;
43
+ mockEffectCleanups = [];
44
+ });
45
+
46
+ it('should initialize hook with default state', () => {
47
+ const mockData = { id: '1', name: 'Test' };
48
+ MockEntity.get.mockReturnValue(of(mockData));
49
+
50
+ const result = useGet(MockEntity as any, '1');
51
+
52
+ expect(result).toBeDefined();
53
+ expect(typeof result.isLoading).toBe('boolean');
54
+ expect(typeof result.hasValue).toBe('boolean');
55
+ });
56
+
57
+ it('should call entity method with correct options', () => {
58
+ MockEntity.get.mockReturnValue(of({ id: '1', name: 'Test' }));
59
+
60
+ useGet(MockEntity as any, '1');
61
+
62
+ expect(MockEntity.get).toHaveBeenCalledWith('1');
63
+ });
64
+
65
+ it('should accept function as options', () => {
66
+ MockEntity.get.mockReturnValue(of({ id: '2', name: 'Dynamic' }));
67
+
68
+ useGet(MockEntity as any, () => '2');
69
+
70
+ expect(MockEntity.get).toHaveBeenCalledWith('2');
71
+ });
72
+ });
73
+
74
+ describe('useFindOne', () => {
75
+ beforeEach(() => {
76
+ vi.clearAllMocks();
77
+ mockState = [];
78
+ mockStateIndex = 0;
79
+ mockEffectCleanups = [];
80
+ });
81
+
82
+ it('should call findOne method', () => {
83
+ MockEntity.findOne.mockReturnValue(of({ id: '1', name: 'Found' }));
84
+
85
+ useFindOne(MockEntity as any, { where: { name: 'Found' } });
86
+
87
+ expect(MockEntity.findOne).toHaveBeenCalledWith({ where: { name: 'Found' } });
88
+ });
89
+ });
90
+
91
+ describe('useFind', () => {
92
+ beforeEach(() => {
93
+ vi.clearAllMocks();
94
+ mockState = [];
95
+ mockStateIndex = 0;
96
+ mockEffectCleanups = [];
97
+ });
98
+
99
+ it('should call find method', () => {
100
+ const mockData = [
101
+ { id: '1', name: 'User1' },
102
+ { id: '2', name: 'User2' }
103
+ ];
104
+ MockEntity.find.mockReturnValue(of(mockData));
105
+
106
+ useFind(MockEntity as any, {});
107
+
108
+ expect(MockEntity.find).toHaveBeenCalled();
109
+ });
110
+ });
111
+
112
+ describe('Hook cleanup', () => {
113
+ beforeEach(() => {
114
+ vi.clearAllMocks();
115
+ mockState = [];
116
+ mockStateIndex = 0;
117
+ mockEffectCleanups = [];
118
+ });
119
+
120
+ it('should register cleanup function', () => {
121
+ MockEntity.get.mockReturnValue(of({ id: '1' }));
122
+
123
+ useGet(MockEntity as any, '1');
124
+
125
+ expect(mockEffectCleanups.length).toBeGreaterThan(0);
126
+ });
127
+ });
package/src/hooks.ts ADDED
@@ -0,0 +1,343 @@
1
+ import { EntityStaticType, EntityType } from '@aiao/rxdb';
2
+ import { isFunction } from '@aiao/utils';
3
+ import { useEffect, useMemo, useRef, useState } from 'react';
4
+ import { Subscription } from 'rxjs';
5
+
6
+ type UseOptions<T> = T | (() => T);
7
+
8
+ export interface RxDBResource<T> {
9
+ /**
10
+ * 资源的数值
11
+ */
12
+ readonly value: T;
13
+ /**
14
+ * 资源的错误
15
+ */
16
+ readonly error: Error | undefined;
17
+ /**
18
+ * 资源的加载状态
19
+ */
20
+ readonly isLoading: boolean;
21
+ /**
22
+ * 资源的空状态
23
+ */
24
+ readonly isEmpty: boolean | undefined;
25
+ /**
26
+ * 资源是否具有数值
27
+ */
28
+ readonly hasValue: boolean;
29
+ }
30
+
31
+ /**
32
+ * RxDB 仓库查询的核心钩子实现
33
+ * 管理响应式订阅和状态更新
34
+ */
35
+ const useRepositoryQuery = <T extends EntityType, RT>(
36
+ EntityType: T,
37
+ method: string,
38
+ defaultValue: RT,
39
+ options: UseOptions<any>
40
+ ): RxDBResource<RT> => {
41
+ // 状态管理
42
+ const [value, setValue] = useState<RT>(defaultValue);
43
+ const [error, setError] = useState<Error | undefined>(undefined);
44
+ const [isLoading, setIsLoading] = useState<boolean>(true);
45
+ const [isEmpty, setIsEmpty] = useState<boolean | undefined>(undefined);
46
+ const [hasValue, setHasValue] = useState<boolean>(false);
47
+
48
+ // 订阅管理
49
+ const subscriptionRef = useRef<Subscription | undefined>(undefined);
50
+ const isMountedRef = useRef(true);
51
+
52
+ const resolvedOptions = useMemo(() => {
53
+ return isFunction(options) ? options() : options;
54
+ }, [options]);
55
+
56
+ useEffect(() => {
57
+ isMountedRef.current = true;
58
+
59
+ // 清理之前的订阅
60
+ if (subscriptionRef.current) {
61
+ subscriptionRef.current.unsubscribe();
62
+ subscriptionRef.current = undefined;
63
+ }
64
+
65
+ // 从 EntityType 获取方法
66
+ // 优化:使用 Record<string, any> 替代 any,以提高类型安全性
67
+ const queryMethod = (EntityType as unknown as Record<string, any>)[method];
68
+
69
+ if (!queryMethod || typeof queryMethod !== 'function') {
70
+ const err = new Error(`Method "${String(method)}" not found on EntityType`);
71
+ Promise.resolve().then(() => {
72
+ if (isMountedRef.current) {
73
+ setError(err);
74
+ setIsLoading(false);
75
+ }
76
+ });
77
+ return;
78
+ }
79
+
80
+ // 执行查询并订阅结果
81
+ try {
82
+ subscriptionRef.current = queryMethod(resolvedOptions).subscribe({
83
+ next: (data: RT) => {
84
+ if (!isMountedRef.current) return;
85
+
86
+ setIsLoading(false);
87
+ setHasValue(true);
88
+ setError(undefined);
89
+
90
+ // 为数组更新空状态
91
+ if (Array.isArray(data)) {
92
+ setIsEmpty(data.length === 0);
93
+ } else {
94
+ setIsEmpty(data == null);
95
+ }
96
+
97
+ setValue(data);
98
+ },
99
+ error: (err: Error) => {
100
+ if (!isMountedRef.current) return;
101
+
102
+ setIsLoading(false);
103
+ setHasValue(false);
104
+ setError(err);
105
+ console.error(`RxDB query error in ${String(method)}:`, err);
106
+ }
107
+ });
108
+ } catch (err) {
109
+ // 延迟状态更新以避免在 effect 中同步 setState
110
+ const error = err instanceof Error ? err : new Error(String(err));
111
+ Promise.resolve().then(() => {
112
+ if (isMountedRef.current) {
113
+ setIsLoading(false);
114
+ setError(error);
115
+ }
116
+ });
117
+ }
118
+
119
+ // 清理函数
120
+ return () => {
121
+ isMountedRef.current = false;
122
+ if (subscriptionRef.current) {
123
+ subscriptionRef.current.unsubscribe();
124
+ subscriptionRef.current = undefined;
125
+ }
126
+ };
127
+ }, [EntityType, method, resolvedOptions]);
128
+
129
+ return {
130
+ value,
131
+ error,
132
+ isLoading,
133
+ isEmpty,
134
+ hasValue
135
+ };
136
+ };
137
+
138
+ /*
139
+ * 仓库钩子
140
+ */
141
+
142
+ /**
143
+ * 通过 ID 获取单个实体
144
+ *
145
+ * @param EntityType 实体类
146
+ * @param options 实体的 ID 或选项对象
147
+ * @returns 包含实体、加载状态和错误的资源对象
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const { value: user, isLoading } = useGet(User, 'user-1');
152
+ * ```
153
+ */
154
+ export const useGet = <T extends EntityType>(
155
+ EntityType: T,
156
+ options: UseOptions<EntityStaticType<T, 'getOptions'>>
157
+ ): RxDBResource<InstanceType<T> | undefined> =>
158
+ useRepositoryQuery<T, InstanceType<T> | undefined>(EntityType, 'get', undefined, options);
159
+
160
+ /**
161
+ * Find one entity matching the criteria
162
+ *
163
+ * @param EntityType The entity class
164
+ * @param options Query options (where clause, sort, etc.)
165
+ * @returns A resource object containing the entity
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const { value: user } = useFindOne(User, { where: { name: 'Alice' } });
170
+ * ```
171
+ */
172
+ export const useFindOne = <T extends EntityType>(
173
+ EntityType: T,
174
+ options: UseOptions<EntityStaticType<T, 'findOneOptions'>>
175
+ ): RxDBResource<InstanceType<T> | undefined> =>
176
+ useRepositoryQuery<T, InstanceType<T> | undefined>(EntityType, 'findOne', undefined, options);
177
+
178
+ /**
179
+ * Find one entity or throw an error if not found
180
+ *
181
+ * @param EntityType The entity class
182
+ * @param options Query options
183
+ * @returns A resource object containing the entity
184
+ */
185
+ export const useFindOneOrFail = <T extends EntityType>(
186
+ EntityType: T,
187
+ options: UseOptions<EntityStaticType<T, 'findOneOrFailOptions'>>
188
+ ): RxDBResource<InstanceType<T> | undefined> =>
189
+ useRepositoryQuery<T, InstanceType<T> | undefined>(EntityType, 'findOneOrFail', undefined, options);
190
+
191
+ /**
192
+ * Find multiple entities matching the criteria
193
+ *
194
+ * @param EntityType The entity class
195
+ * @param options Query options
196
+ * @returns A resource object containing an array of entities
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const { value: users } = useFind(User, { where: { age: { $gt: 18 } } });
201
+ * ```
202
+ */
203
+ export const useFind = <T extends EntityType>(
204
+ EntityType: T,
205
+ options: UseOptions<EntityStaticType<T, 'findOptions'>>
206
+ ): RxDBResource<InstanceType<T>[]> => useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'find', [], options);
207
+
208
+ /**
209
+ * Find all entities
210
+ *
211
+ * @param EntityType The entity class
212
+ * @param options Query options
213
+ * @returns A resource object containing all entities
214
+ */
215
+ export const useFindAll = <T extends EntityType>(
216
+ EntityType: T,
217
+ options: UseOptions<EntityStaticType<T, 'findAllOptions'>>
218
+ ): RxDBResource<InstanceType<T>[]> => useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findAll', [], options);
219
+
220
+ /**
221
+ * Count entities matching the criteria
222
+ *
223
+ * @param EntityType The entity class
224
+ * @param options Query options
225
+ * @returns A resource object containing the count
226
+ */
227
+ export const useCount = <T extends EntityType>(
228
+ EntityType: T,
229
+ options: UseOptions<EntityStaticType<T, 'countOptions'>>
230
+ ): RxDBResource<number> => useRepositoryQuery<T, number>(EntityType, 'count', 0, options);
231
+
232
+ /*
233
+ * Tree Repository Hooks
234
+ */
235
+
236
+ /**
237
+ * Find all descendant entities in a tree structure
238
+ *
239
+ * @param EntityType The entity class
240
+ * @param options Tree query options (entityId, depth, etc.)
241
+ * @returns A resource object containing descendant entities
242
+ */
243
+ export const useFindDescendants = <T extends EntityType>(
244
+ EntityType: T,
245
+ options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>
246
+ ): RxDBResource<InstanceType<T>[]> =>
247
+ useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findDescendants', [], options);
248
+
249
+ /**
250
+ * Count descendant entities in a tree structure
251
+ *
252
+ * @param EntityType The entity class
253
+ * @param options Tree query options
254
+ * @returns A resource object containing the count
255
+ */
256
+ export const useCountDescendants = <T extends EntityType>(
257
+ EntityType: T,
258
+ options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>
259
+ ): RxDBResource<number> => useRepositoryQuery<T, number>(EntityType, 'countDescendants', 0, options);
260
+
261
+ /**
262
+ * Find all ancestor entities in a tree structure
263
+ *
264
+ * @param EntityType The entity class
265
+ * @param options Tree query options
266
+ * @returns A resource object containing ancestor entities
267
+ */
268
+ export const useFindAncestors = <T extends EntityType>(
269
+ EntityType: T,
270
+ options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>
271
+ ): RxDBResource<InstanceType<T>[]> =>
272
+ useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findAncestors', [], options);
273
+
274
+ /**
275
+ * Count ancestor entities in a tree structure
276
+ *
277
+ * @param EntityType The entity class
278
+ * @param options Tree query options
279
+ * @returns A resource object containing the count
280
+ */
281
+ export const useCountAncestors = <T extends EntityType>(
282
+ EntityType: T,
283
+ options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>
284
+ ): RxDBResource<number> => useRepositoryQuery<T, number>(EntityType, 'countAncestors', 0, options);
285
+
286
+ /*
287
+ * Graph Repository Hooks
288
+ */
289
+
290
+ /**
291
+ * Find neighbor entities in a graph structure
292
+ *
293
+ * @param EntityType The entity class
294
+ * @param options Graph query options (entityId, direction, level, etc.)
295
+ * @returns A resource object containing neighbor entities
296
+ *
297
+ * @example
298
+ * ```typescript
299
+ * const { value: friends } = useGraphNeighbors(User, {
300
+ * entityId: 'user-1',
301
+ * direction: 'out',
302
+ * level: 1
303
+ * });
304
+ * ```
305
+ */
306
+ export const useGraphNeighbors = <T extends EntityType>(
307
+ EntityType: T,
308
+ options: UseOptions<EntityStaticType<T, 'findNeighborsOptions'>>
309
+ ): RxDBResource<InstanceType<T>[]> =>
310
+ useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findNeighbors', [], options);
311
+
312
+ /**
313
+ * Count neighbor entities in a graph structure
314
+ *
315
+ * @param EntityType The entity class
316
+ * @param options Graph query options
317
+ * @returns A resource object containing the count
318
+ */
319
+ export const useCountNeighbors = <T extends EntityType>(
320
+ EntityType: T,
321
+ options: UseOptions<EntityStaticType<T, 'findNeighborsOptions'>>
322
+ ): RxDBResource<number> => useRepositoryQuery<T, number>(EntityType, 'countNeighbors', 0, options);
323
+
324
+ /**
325
+ * Find paths between two entities in a graph
326
+ *
327
+ * @param EntityType The entity class
328
+ * @param options Path query options (fromId, toId, maxDepth, etc.)
329
+ * @returns A resource object containing paths
330
+ *
331
+ * @example
332
+ * ```typescript
333
+ * const { value: paths } = useGraphPaths(User, {
334
+ * fromId: 'user-1',
335
+ * toId: 'user-2',
336
+ * maxDepth: 5
337
+ * });
338
+ * ```
339
+ */
340
+ export const useGraphPaths = <T extends EntityType>(
341
+ EntityType: T,
342
+ options: UseOptions<EntityStaticType<T, 'findPathsOptions'>>
343
+ ): RxDBResource<any[]> => useRepositoryQuery<T, any[]>(EntityType, 'findPaths', [], options);
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './hooks';
2
+ export * from './rxdb-react';
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { makeRxDBProvider, RxDBProvider, useRxDB } from './rxdb-react';
4
+
5
+ describe('makeRxDBProvider', () => {
6
+ it('should create RxDBProvider and useRxDB hook', () => {
7
+ const { RxDBProvider, useRxDB } = makeRxDBProvider();
8
+
9
+ expect(RxDBProvider).toBeDefined();
10
+ expect(useRxDB).toBeDefined();
11
+ expect(typeof RxDBProvider).toBe('function');
12
+ expect(typeof useRxDB).toBe('function');
13
+ });
14
+
15
+ it('should create context provider component', () => {
16
+ const mockDB = { name: 'test-db' } as any;
17
+ const { RxDBProvider } = makeRxDBProvider();
18
+
19
+ const element = React.createElement(RxDBProvider, { db: mockDB }, 'children');
20
+
21
+ expect(element).toBeDefined();
22
+ expect(element.type).toBe(RxDBProvider);
23
+ });
24
+ });
25
+
26
+ describe('Default exports', () => {
27
+ it('should export default RxDBProvider', () => {
28
+ expect(RxDBProvider).toBeDefined();
29
+ expect(typeof RxDBProvider).toBe('function');
30
+ });
31
+
32
+ it('should export default useRxDB', () => {
33
+ expect(useRxDB).toBeDefined();
34
+ expect(typeof useRxDB).toBe('function');
35
+ });
36
+
37
+ it('should export makeRxDBProvider function', () => {
38
+ expect(makeRxDBProvider).toBeDefined();
39
+ expect(typeof makeRxDBProvider).toBe('function');
40
+ });
41
+ });
@@ -0,0 +1,38 @@
1
+ import { RxDB } from '@aiao/rxdb';
2
+ import React, { createContext, useContext } from 'react';
3
+
4
+ interface Props<T extends RxDB> {
5
+ children?: React.ReactNode;
6
+ db?: T;
7
+ }
8
+
9
+ type RxDBProviderType<T extends RxDB> = (props: Props<T>) => React.JSX.Element;
10
+ type UseRxDB<T extends RxDB> = (db?: T) => T;
11
+
12
+ interface RxDBProviderSet<T extends RxDB> {
13
+ RxDBProvider: RxDBProviderType<T>;
14
+ useRxDB: UseRxDB<T>;
15
+ }
16
+
17
+ /**
18
+ * RxDB 依赖注入
19
+ */
20
+ function makeRxDBProvider<T extends RxDB>(): RxDBProviderSet<T> {
21
+ const ctx = createContext<T | undefined>(undefined);
22
+ return {
23
+ useRxDB: ((db?: T) => {
24
+ const dbProvided = useContext(ctx);
25
+ if (db !== undefined) return db;
26
+ if (!dbProvided) throw new Error('No RxDB instance found, use RxDBProvider to provide one');
27
+
28
+ return dbProvided;
29
+ }) as UseRxDB<T>,
30
+ RxDBProvider: ({ children, db }: Props<T>) => {
31
+ return <ctx.Provider value={db}>{children}</ctx.Provider>;
32
+ }
33
+ };
34
+ }
35
+
36
+ const { RxDBProvider, useRxDB } = makeRxDBProvider<RxDB>();
37
+
38
+ export { makeRxDBProvider, RxDBProvider, useRxDB };
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "files": [],
4
+ "include": [],
5
+ "references": [
6
+ {
7
+ "path": "./tsconfig.lib.json"
8
+ },
9
+ {
10
+ "path": "./tsconfig.spec.json"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "dist",
4
+ "types": ["node", "@nx/react/typings/cssmodule.d.ts", "@nx/react/typings/image.d.ts", "vite/client"],
5
+ "rootDir": "src",
6
+ "jsx": "react-jsx",
7
+ "module": "esnext",
8
+ "moduleResolution": "bundler",
9
+ "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo"
10
+ },
11
+ "exclude": [
12
+ "out-tsc",
13
+ "dist",
14
+ "**/*.spec.ts",
15
+ "**/*.test.ts",
16
+ "**/*.spec.tsx",
17
+ "**/*.test.tsx",
18
+ "**/*.spec.js",
19
+ "**/*.test.js",
20
+ "**/*.spec.jsx",
21
+ "**/*.test.jsx",
22
+ "vite.config.ts",
23
+ "vite.config.mts",
24
+ "vitest.config.ts",
25
+ "vitest.config.mts",
26
+ "src/**/*.test.ts",
27
+ "src/**/*.spec.ts",
28
+ "src/**/*.test.tsx",
29
+ "src/**/*.spec.tsx",
30
+ "src/**/*.test.js",
31
+ "src/**/*.spec.js",
32
+ "src/**/*.test.jsx",
33
+ "src/**/*.spec.jsx",
34
+ "eslint.config.js",
35
+ "eslint.config.cjs",
36
+ "eslint.config.mjs"
37
+ ],
38
+ "extends": "../../tsconfig.base.json",
39
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"],
40
+ "references": [
41
+ {
42
+ "path": "../utils/tsconfig.lib.json"
43
+ },
44
+ {
45
+ "path": "../rxdb/tsconfig.lib.json"
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./out-tsc/vitest",
4
+ "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"],
5
+ "jsx": "react-jsx",
6
+ "module": "esnext",
7
+ "moduleResolution": "bundler"
8
+ },
9
+ "extends": "../../tsconfig.base.json",
10
+ "include": [
11
+ "vite.config.ts",
12
+ "vite.config.mts",
13
+ "vitest.config.ts",
14
+ "vitest.config.mts",
15
+ "src/**/*.test.ts",
16
+ "src/**/*.spec.ts",
17
+ "src/**/*.test.tsx",
18
+ "src/**/*.spec.tsx",
19
+ "src/**/*.test.js",
20
+ "src/**/*.spec.js",
21
+ "src/**/*.test.jsx",
22
+ "src/**/*.spec.jsx",
23
+ "src/**/*.d.ts"
24
+ ],
25
+ "references": [
26
+ {
27
+ "path": "./tsconfig.lib.json"
28
+ }
29
+ ]
30
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,80 @@
1
+ /// <reference types='vitest' />
2
+ import { codecovVitePlugin } from '@codecov/vite-plugin';
3
+ import react from '@vitejs/plugin-react';
4
+ import * as path from 'path';
5
+ import dts from 'vite-plugin-dts';
6
+ import { defineConfig } from 'vitest/config';
7
+
8
+ export default defineConfig({
9
+ root: __dirname,
10
+ cacheDir: '../../node_modules/.vite/packages/rxdb-react',
11
+ plugins: [
12
+ react(),
13
+ dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') }),
14
+ // Codecov Bundle Analysis - 仅在 CI 环境中启用
15
+ // TECH DEBT: @codecov/vite-plugin@1.9.1 不支持 Vite 7.x (仅支持 4/5/6)
16
+ // 临时使用类型断言绕过编译错误,功能运行时正常
17
+ // TODO: 等待上游支持 Vite 7 后移除 as any
18
+ ...(process.env.CI === 'true' && process.env.CODECOV_TOKEN ?
19
+ [
20
+ codecovVitePlugin({
21
+ enableBundleAnalysis: true,
22
+ telemetry: false,
23
+ bundleName: 'rxdb-react',
24
+ uploadToken: process.env.CODECOV_TOKEN
25
+ }) as any
26
+ ]
27
+ : [])
28
+ ],
29
+ // Uncomment this if you are using workers.
30
+ // worker: {
31
+ // plugins: [ nxViteTsPaths() ],
32
+ // },
33
+ // Configuration for building your library.
34
+ // See: https://vitejs.dev/guide/build.html#library-mode
35
+ build: {
36
+ outDir: './dist',
37
+ emptyOutDir: true,
38
+ reportCompressedSize: true,
39
+ commonjsOptions: {
40
+ transformMixedEsModules: true
41
+ },
42
+ lib: {
43
+ // Could also be a dictionary or array of multiple entry points.
44
+ entry: 'src/index.ts',
45
+ name: 'rxdb-react',
46
+ fileName: 'index',
47
+ // Change this to the formats you want to support.
48
+ // Don't forget to update your package.json as well.
49
+ formats: ['es' as const]
50
+ },
51
+ rollupOptions: {
52
+ // External packages that should not be bundled into your library.
53
+ external: ['react', 'react-dom', 'react/jsx-runtime', '@aiao/rxdb', '@aiao/utils', 'rxjs']
54
+ }
55
+ },
56
+ optimizeDeps: {
57
+ exclude: ['rxjs', 'ms', 'fastest-levenshtein', 'ts-xor', '@aiao/rxdb', '@aiao/utils']
58
+ },
59
+ test: {
60
+ name: 'rxdb-react',
61
+ watch: false,
62
+ globals: true,
63
+ environment: 'happy-dom',
64
+ passWithNoTests: true,
65
+ testTimeout: 2000,
66
+ hookTimeout: 2000,
67
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
68
+ reporters: ['default', 'junit'],
69
+ outputFile: {
70
+ junit: '../../coverage/packages/rxdb-react/junit.xml'
71
+ },
72
+ coverage: {
73
+ enabled: true,
74
+ reportsDirectory: '../../coverage/packages/rxdb-react',
75
+ provider: 'v8',
76
+ include: ['src/**/*'],
77
+ exclude: ['**/index.ts', '**/dist/**']
78
+ }
79
+ }
80
+ });