@aiao/rxdb-angular 0.0.3 → 0.0.8
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 +21 -0
- package/fesm2022/aiao-rxdb-angular.mjs +406 -30
- package/fesm2022/aiao-rxdb-angular.mjs.map +1 -1
- package/package.json +10 -7
- package/types/aiao-rxdb-angular.d.ts +222 -0
- package/index.d.ts +0 -15
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.
|
|
@@ -1,47 +1,423 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isPlatformBrowser } from '@angular/common';
|
|
1
|
+
import { isFunction, nextMicroTask, IS_BROWSER } from '@aiao/utils';
|
|
3
2
|
import * as i0 from '@angular/core';
|
|
4
|
-
import {
|
|
3
|
+
import { signal, effect, inject, DestroyRef, computed, untracked, ChangeDetectorRef, input, Directive, makeEnvironmentProviders } from '@angular/core';
|
|
4
|
+
import { toLazySignal } from 'ngxtension/to-lazy-signal';
|
|
5
|
+
import { Observable, debounceTime, auditTime } from 'rxjs';
|
|
6
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
7
|
+
import { getEntityStatus, RxDB } from '@aiao/rxdb';
|
|
5
8
|
|
|
6
|
-
const
|
|
9
|
+
const useRepositoryQuery = (EntityType, method, defaultValue, options) => {
|
|
10
|
+
let _observer;
|
|
11
|
+
let sub;
|
|
12
|
+
const _has_sub = signal(false, ...(ngDevMode ? [{ debugName: "_has_sub" }] : []));
|
|
13
|
+
const _refresh = signal(0, ...(ngDevMode ? [{ debugName: "_refresh" }] : []));
|
|
14
|
+
const _eff = effect(() => {
|
|
15
|
+
if (_has_sub() === false)
|
|
16
|
+
return;
|
|
17
|
+
// re-run when refresh is called or options change
|
|
18
|
+
_refresh();
|
|
19
|
+
const opt = isFunction(options) ? options() : options;
|
|
20
|
+
if (sub)
|
|
21
|
+
sub.unsubscribe();
|
|
22
|
+
// reset state for a new request
|
|
23
|
+
isLoading.set(true);
|
|
24
|
+
error.set(undefined);
|
|
25
|
+
hasValue.set(false);
|
|
26
|
+
isEmpty.set(undefined);
|
|
27
|
+
// 优化:使用 Record<string, any> 替代 any,以提高类型安全性
|
|
28
|
+
const func = EntityType[method];
|
|
29
|
+
sub =
|
|
30
|
+
func &&
|
|
31
|
+
func(opt).subscribe({
|
|
32
|
+
next: (d) => {
|
|
33
|
+
isLoading.set(false);
|
|
34
|
+
hasValue.set(true);
|
|
35
|
+
if (Array.isArray(d)) {
|
|
36
|
+
isEmpty.set(d.length === 0);
|
|
37
|
+
}
|
|
38
|
+
else if (d == null) {
|
|
39
|
+
// null/undefined treated as empty
|
|
40
|
+
isEmpty.set(true);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
isEmpty.set(false);
|
|
44
|
+
}
|
|
45
|
+
_observer.next(d);
|
|
46
|
+
},
|
|
47
|
+
error: (e) => {
|
|
48
|
+
isLoading.set(false);
|
|
49
|
+
error.set(e);
|
|
50
|
+
},
|
|
51
|
+
complete: () => {
|
|
52
|
+
// ensure loading is false even if observable completes without next
|
|
53
|
+
isLoading.set(false);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}, ...(ngDevMode ? [{ debugName: "_eff" }] : []));
|
|
57
|
+
const ob = new Observable(observer => {
|
|
58
|
+
_has_sub.set(true);
|
|
59
|
+
_observer = observer;
|
|
60
|
+
_observer.next(defaultValue);
|
|
61
|
+
return () => {
|
|
62
|
+
_eff.destroy();
|
|
63
|
+
sub?.unsubscribe();
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
const value = toLazySignal(ob, {
|
|
67
|
+
initialValue: defaultValue
|
|
68
|
+
});
|
|
69
|
+
const error = signal(undefined, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
70
|
+
const isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
71
|
+
const hasValue = signal(false, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
|
|
72
|
+
const isEmpty = signal(undefined, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
|
|
73
|
+
return {
|
|
74
|
+
value,
|
|
75
|
+
error,
|
|
76
|
+
isLoading,
|
|
77
|
+
isEmpty,
|
|
78
|
+
hasValue
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
/*
|
|
82
|
+
* Repository
|
|
83
|
+
*/
|
|
84
|
+
/**
|
|
85
|
+
* 通过 ID 获取单个实体
|
|
86
|
+
*
|
|
87
|
+
* @param EntityType 实体类
|
|
88
|
+
* @param options 实体 ID 或查询参数对象
|
|
89
|
+
* @returns 返回包含实体的资源 signal
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const user = useGet(User, 'user-1');
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
const useGet = (EntityType, options) => useRepositoryQuery(EntityType, 'get', undefined, options);
|
|
97
|
+
/**
|
|
98
|
+
* 查找第一个匹配条件的实体
|
|
99
|
+
*
|
|
100
|
+
* @param EntityType 实体类
|
|
101
|
+
* @param options 查询参数(where、排序等)
|
|
102
|
+
* @returns 返回包含实体的资源 signal
|
|
103
|
+
*/
|
|
104
|
+
const useFindOne = (EntityType, options) => useRepositoryQuery(EntityType, 'findOne', undefined, options);
|
|
105
|
+
/**
|
|
106
|
+
* 查找匹配的实体,未找到则抛出错误
|
|
107
|
+
*
|
|
108
|
+
* @param EntityType 实体类
|
|
109
|
+
* @param options 查询参数
|
|
110
|
+
* @returns 返回包含实体的资源 signal
|
|
111
|
+
*/
|
|
112
|
+
const useFindOneOrFail = (EntityType, options) => useRepositoryQuery(EntityType, 'findOneOrFail', undefined, options);
|
|
113
|
+
/**
|
|
114
|
+
* 查找符合条件的多个实体
|
|
115
|
+
*
|
|
116
|
+
* @param EntityType 实体类
|
|
117
|
+
* @param options 查询参数
|
|
118
|
+
* @returns 返回包含实体数组的资源 signal
|
|
119
|
+
*/
|
|
120
|
+
const useFind = (EntityType, options) => useRepositoryQuery(EntityType, 'find', [], options);
|
|
121
|
+
/**
|
|
122
|
+
* 使用游标分页查找实体
|
|
123
|
+
*
|
|
124
|
+
* @param EntityType 实体类
|
|
125
|
+
* @param options 游标参数
|
|
126
|
+
* @returns 返回包含实体数组的资源 signal
|
|
127
|
+
*/
|
|
128
|
+
const useFindByCursor = (EntityType, options) => useRepositoryQuery(EntityType, 'findByCursor', [], options);
|
|
129
|
+
/**
|
|
130
|
+
* 查找全部实体
|
|
131
|
+
*
|
|
132
|
+
* @param EntityType 实体类
|
|
133
|
+
* @param options 查询参数
|
|
134
|
+
* @returns 返回包含全部实体的资源 signal
|
|
135
|
+
*/
|
|
136
|
+
const useFindAll = (EntityType, options) => useRepositoryQuery(EntityType, 'findAll', [], options);
|
|
137
|
+
/**
|
|
138
|
+
* 统计满足条件的实体数量
|
|
139
|
+
*
|
|
140
|
+
* @param EntityType 实体类
|
|
141
|
+
* @param options 查询参数
|
|
142
|
+
* @returns 返回包含数量的资源 signal
|
|
143
|
+
*/
|
|
144
|
+
const useCount = (EntityType, options) => useRepositoryQuery(EntityType, 'count', undefined, options);
|
|
145
|
+
/*
|
|
146
|
+
* TreeRepository
|
|
147
|
+
*/
|
|
148
|
+
/**
|
|
149
|
+
* 查找树结构中的所有子孙实体
|
|
150
|
+
*
|
|
151
|
+
* @param EntityType 实体类
|
|
152
|
+
* @param options 树查询参数(entityId、深度等)
|
|
153
|
+
* @returns 返回包含子孙实体的资源 signal
|
|
154
|
+
*/
|
|
155
|
+
const useFindDescendants = (EntityType, options) => useRepositoryQuery(EntityType, 'findDescendants', [], options);
|
|
156
|
+
/**
|
|
157
|
+
* 统计树结构中的子孙数量
|
|
158
|
+
*
|
|
159
|
+
* @param EntityType 实体类
|
|
160
|
+
* @param options 树查询参数
|
|
161
|
+
* @returns 返回包含数量的资源 signal
|
|
162
|
+
*/
|
|
163
|
+
const useCountDescendants = (EntityType, options) => useRepositoryQuery(EntityType, 'countDescendants', undefined, options);
|
|
164
|
+
/**
|
|
165
|
+
* 查找树结构中的所有祖先实体
|
|
166
|
+
*
|
|
167
|
+
* @param EntityType 实体类
|
|
168
|
+
* @param options 树查询参数
|
|
169
|
+
* @returns 返回包含祖先实体的资源 signal
|
|
170
|
+
*/
|
|
171
|
+
const useFindAncestors = (EntityType, options) => useRepositoryQuery(EntityType, 'findAncestors', [], options);
|
|
172
|
+
/**
|
|
173
|
+
* 统计树结构中的祖先数量
|
|
174
|
+
*
|
|
175
|
+
* @param EntityType 实体类
|
|
176
|
+
* @param options 树查询参数
|
|
177
|
+
* @returns 返回包含数量的资源 signal
|
|
178
|
+
*/
|
|
179
|
+
const useCountAncestors = (EntityType, options) => useRepositoryQuery(EntityType, 'countAncestors', undefined, options);
|
|
180
|
+
/*
|
|
181
|
+
* GraphRepository
|
|
182
|
+
*/
|
|
183
|
+
/**
|
|
184
|
+
* 查找图结构中的邻接实体
|
|
185
|
+
*
|
|
186
|
+
* @param EntityType 实体类
|
|
187
|
+
* @param options 图查询参数(entityId、方向、层级等)
|
|
188
|
+
* @returns 返回包含邻居实体的资源 signal
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* const friends = useGraphNeighbors(User, {
|
|
193
|
+
* entityId: 'user-1',
|
|
194
|
+
* direction: 'out',
|
|
195
|
+
* level: 1
|
|
196
|
+
* });
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
const useGraphNeighbors = (EntityType, options) => useRepositoryQuery(EntityType, 'findNeighbors', [], options);
|
|
200
|
+
/**
|
|
201
|
+
* 统计图结构中的邻接数量
|
|
202
|
+
*
|
|
203
|
+
* @param EntityType 实体类
|
|
204
|
+
* @param options 图查询参数
|
|
205
|
+
* @returns 返回包含数量的资源 signal
|
|
206
|
+
*/
|
|
207
|
+
const useCountNeighbors = (EntityType, options) => useRepositoryQuery(EntityType, 'countNeighbors', 0, options);
|
|
208
|
+
/**
|
|
209
|
+
* 查找图结构中两个实体之间的路径
|
|
210
|
+
*
|
|
211
|
+
* @param EntityType 实体类
|
|
212
|
+
* @param options 路径查询参数(fromId、toId、最大深度等)
|
|
213
|
+
* @returns 返回包含路径的资源 signal
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* const paths = useGraphPaths(User, {
|
|
218
|
+
* fromId: 'user-1',
|
|
219
|
+
* toId: 'user-2',
|
|
220
|
+
* maxDepth: 5
|
|
221
|
+
* });
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
const useGraphPaths = (EntityType, options) => useRepositoryQuery(EntityType, 'findPaths', [], options);
|
|
7
225
|
|
|
8
226
|
/**
|
|
9
|
-
*
|
|
227
|
+
* 无限滚动的列表
|
|
10
228
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
229
|
+
class InfiniteScrollingList {
|
|
230
|
+
rxdb;
|
|
231
|
+
EntityType;
|
|
232
|
+
options;
|
|
233
|
+
#values = signal([], ...(ngDevMode ? [{ debugName: "#values" }] : []));
|
|
234
|
+
#destroy_ref = inject(DestroyRef);
|
|
235
|
+
#options_eff;
|
|
236
|
+
#is_initialized = false;
|
|
237
|
+
error = signal(undefined, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
238
|
+
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
239
|
+
hasMore = signal(true, ...(ngDevMode ? [{ debugName: "hasMore" }] : []));
|
|
240
|
+
value = computed(() => this.#values().flat(), ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
241
|
+
hasValue = computed(() => this.value().length > 0, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
|
|
242
|
+
isEmpty = computed(() => !this.isLoading() && !this.hasValue() && this.#is_initialized, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
|
|
243
|
+
constructor(rxdb, EntityType, options) {
|
|
244
|
+
this.rxdb = rxdb;
|
|
245
|
+
this.EntityType = EntityType;
|
|
246
|
+
this.options = options;
|
|
247
|
+
this.#options_eff = effect(() => {
|
|
248
|
+
if (isFunction(this.options)) {
|
|
249
|
+
this.options();
|
|
250
|
+
}
|
|
251
|
+
if (!this.#is_initialized) {
|
|
252
|
+
this.#is_initialized = true;
|
|
253
|
+
nextMicroTask(() => this.loadMore());
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
untracked(() => this.#reset());
|
|
257
|
+
}, ...(ngDevMode ? [{ debugName: "#options_eff" }] : []));
|
|
258
|
+
this.#destroy_ref.onDestroy(() => {
|
|
259
|
+
this.#options_eff.destroy();
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
loadMore() {
|
|
263
|
+
if (this.isLoading() || !this.hasMore()) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
this.isLoading.set(true);
|
|
267
|
+
this.error.set(undefined);
|
|
268
|
+
const last_entity = this.#get_last_entity();
|
|
269
|
+
const opt = isFunction(this.options) ? this.options() : this.options;
|
|
270
|
+
const options = structuredClone(opt);
|
|
271
|
+
if (last_entity) {
|
|
272
|
+
options.after = last_entity;
|
|
273
|
+
}
|
|
274
|
+
const current_index = this.#values().length;
|
|
275
|
+
this.rxdb.entityManager
|
|
276
|
+
.getRepository(this.EntityType)
|
|
277
|
+
.findByCursor(options)
|
|
278
|
+
.pipe(takeUntilDestroyed(this.#destroy_ref))
|
|
279
|
+
.subscribe({
|
|
280
|
+
next: result => {
|
|
281
|
+
this.isLoading.set(false);
|
|
282
|
+
this.#values.update(values => {
|
|
283
|
+
const updated = [...values];
|
|
284
|
+
updated[current_index] = result;
|
|
285
|
+
return updated;
|
|
286
|
+
});
|
|
287
|
+
if (result.length < (options.limit || 100)) {
|
|
288
|
+
this.hasMore.set(false);
|
|
25
289
|
}
|
|
26
|
-
return null;
|
|
27
290
|
},
|
|
28
|
-
|
|
291
|
+
error: error => {
|
|
292
|
+
this.isLoading.set(false);
|
|
293
|
+
this.error.set(error);
|
|
294
|
+
},
|
|
295
|
+
complete: () => {
|
|
296
|
+
this.hasMore.set(false);
|
|
297
|
+
this.isLoading.set(false);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 刷新列表数据
|
|
303
|
+
*/
|
|
304
|
+
refresh() {
|
|
305
|
+
// 强制重置状态,即使正在加载中
|
|
306
|
+
this.#values.set([]);
|
|
307
|
+
this.error.set(undefined);
|
|
308
|
+
this.isLoading.set(false); // 强制设置为 false,允许新的 loadMore
|
|
309
|
+
this.hasMore.set(true);
|
|
310
|
+
// 立即开始加载
|
|
311
|
+
this.loadMore();
|
|
312
|
+
}
|
|
313
|
+
#reset() {
|
|
314
|
+
this.#values.set([]);
|
|
315
|
+
this.error.set(undefined);
|
|
316
|
+
this.isLoading.set(false);
|
|
317
|
+
this.hasMore.set(true);
|
|
318
|
+
nextMicroTask(() => this.loadMore());
|
|
319
|
+
}
|
|
320
|
+
#get_last_entity() {
|
|
321
|
+
const values = this.#values();
|
|
322
|
+
if (values.length === 0)
|
|
323
|
+
return undefined;
|
|
324
|
+
const last_page = values[values.length - 1];
|
|
325
|
+
if (last_page.length === 0)
|
|
326
|
+
return undefined;
|
|
327
|
+
return last_page[last_page.length - 1];
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* RxDB 实体变化指令
|
|
333
|
+
* 如果你使用了 `changeDetection: ChangeDetectionStrategy.OnPush`
|
|
334
|
+
* 那么正在输入的变化不会触发 angular 渲染机制,使用这个指令可以实现实时渲染
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* 当修改实体时,需要在多个地方预览修改变化时,可以使用这个指令
|
|
338
|
+
*/
|
|
339
|
+
class RxDBEntityChangeDirective {
|
|
340
|
+
#destroyRef = inject(DestroyRef);
|
|
341
|
+
#changeDetectorRef = inject(ChangeDetectorRef);
|
|
342
|
+
#sub;
|
|
343
|
+
rxdbChangeDetector = input(...(ngDevMode ? [undefined, { debugName: "rxdbChangeDetector" }] : []));
|
|
344
|
+
debounceTime = input(0, ...(ngDevMode ? [{ debugName: "debounceTime" }] : []));
|
|
345
|
+
auditTime = input(0, ...(ngDevMode ? [{ debugName: "auditTime" }] : []));
|
|
346
|
+
constructor() {
|
|
347
|
+
effect(() => {
|
|
348
|
+
const rxdbChange = this.rxdbChangeDetector();
|
|
349
|
+
const dt = this.debounceTime();
|
|
350
|
+
const at = this.auditTime();
|
|
351
|
+
const status = getEntityStatus(rxdbChange);
|
|
352
|
+
this.#sub?.unsubscribe();
|
|
353
|
+
this.#sub = status.patches$
|
|
354
|
+
.pipe(takeUntilDestroyed(this.#destroyRef), debounceTime(dt), auditTime(at))
|
|
355
|
+
.subscribe(() => this.#changeDetectorRef.markForCheck());
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RxDBEntityChangeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
359
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: RxDBEntityChangeDirective, isStandalone: true, selector: "[rxdbChangeDetector]", inputs: { rxdbChangeDetector: { classPropertyName: "rxdbChangeDetector", publicName: "rxdbChangeDetector", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null }, auditTime: { classPropertyName: "auditTime", publicName: "auditTime", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
360
|
+
}
|
|
361
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RxDBEntityChangeDirective, decorators: [{
|
|
362
|
+
type: Directive,
|
|
363
|
+
args: [{ selector: '[rxdbChangeDetector]' }]
|
|
364
|
+
}], ctorParameters: () => [], propDecorators: { rxdbChangeDetector: [{ type: i0.Input, args: [{ isSignal: true, alias: "rxdbChangeDetector", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], auditTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "auditTime", required: false }] }] } });
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* RxDB 配置
|
|
368
|
+
*/
|
|
369
|
+
const provideRxDB = (useFactory) => makeEnvironmentProviders([
|
|
370
|
+
{
|
|
371
|
+
provide: RxDB,
|
|
372
|
+
useFactory
|
|
373
|
+
}
|
|
374
|
+
]);
|
|
375
|
+
|
|
376
|
+
const action = (promiseFn) => {
|
|
377
|
+
const isPending = signal(false, ...(ngDevMode ? [{ debugName: "isPending" }] : []));
|
|
378
|
+
return {
|
|
379
|
+
isPending,
|
|
380
|
+
execute: async (options) => {
|
|
381
|
+
isPending.set(true);
|
|
382
|
+
try {
|
|
383
|
+
const d = await promiseFn(options);
|
|
384
|
+
return d;
|
|
385
|
+
}
|
|
386
|
+
finally {
|
|
387
|
+
isPending.set(false);
|
|
388
|
+
}
|
|
29
389
|
}
|
|
30
|
-
|
|
390
|
+
};
|
|
31
391
|
};
|
|
392
|
+
const useAction = (promiseFn) => action(promiseFn);
|
|
32
393
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
394
|
+
function state(namespace) {
|
|
395
|
+
return (name) => {
|
|
396
|
+
const signal$1 = (initialValue, options) => {
|
|
397
|
+
if (IS_BROWSER) {
|
|
398
|
+
const value = localStorage.getItem(`${namespace}:${name}`);
|
|
399
|
+
if (value) {
|
|
400
|
+
initialValue = JSON.parse(value);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const a = signal(initialValue, options);
|
|
404
|
+
effect(() => {
|
|
405
|
+
if (IS_BROWSER) {
|
|
406
|
+
localStorage.setItem(`${namespace}:${name}`, JSON.stringify(a()));
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
return a;
|
|
410
|
+
};
|
|
411
|
+
return {
|
|
412
|
+
signal: signal$1
|
|
413
|
+
};
|
|
414
|
+
};
|
|
36
415
|
}
|
|
37
|
-
|
|
38
|
-
type: Injectable,
|
|
39
|
-
args: [{ providedIn: 'root' }]
|
|
40
|
-
}] });
|
|
416
|
+
const useState = (namespace) => state(namespace);
|
|
41
417
|
|
|
42
418
|
/**
|
|
43
419
|
* Generated bundle index. Do not edit.
|
|
44
420
|
*/
|
|
45
421
|
|
|
46
|
-
export {
|
|
422
|
+
export { InfiniteScrollingList, RxDBEntityChangeDirective, provideRxDB, useAction, useCount, useCountAncestors, useCountDescendants, useCountNeighbors, useFind, useFindAll, useFindAncestors, useFindByCursor, useFindDescendants, useFindOne, useFindOneOrFail, useGet, useGraphNeighbors, useGraphPaths, useRepositoryQuery, useState };
|
|
47
423
|
//# sourceMappingURL=aiao-rxdb-angular.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiao-rxdb-angular.mjs","sources":["../tmp-esm2022/rxdb.interface.js","../tmp-esm2022/rxdb.provider.js","../tmp-esm2022/rxdb.service.js","../tmp-esm2022/aiao-rxdb-angular.js"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nexport const RXDB_OPTIONS = new InjectionToken('RXDB_OPTIONS');\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnhkYi5pbnRlcmZhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wYWNrYWdlcy9yeGRiLWFuZ3VsYXIvc3JjL3J4ZGIuaW50ZXJmYWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFL0MsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLElBQUksY0FBYyxDQUFjLGNBQWMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUnhEQk9wdGlvbnMgfSBmcm9tICdAYWlhby9yeGRiJztcbmltcG9ydCB7IEluamVjdGlvblRva2VuIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmV4cG9ydCBjb25zdCBSWERCX09QVElPTlMgPSBuZXcgSW5qZWN0aW9uVG9rZW48UnhEQk9wdGlvbnM+KCdSWERCX09QVElPTlMnKTtcbiJdfQ==","import { RxDB } from '@aiao/rxdb';\nimport { isPlatformBrowser } from '@angular/common';\nimport { PLATFORM_ID } from '@angular/core';\nimport { RXDB_OPTIONS } from './rxdb.interface';\n/**\n * RxDB 配置\n */\nexport const provideRxDB = (options, callback) => {\n return [\n {\n provide: RXDB_OPTIONS,\n useValue: options\n },\n {\n provide: RxDB,\n useFactory: (options, platformId) => {\n if (isPlatformBrowser(platformId)) {\n const db = new RxDB(options);\n if (callback)\n callback(db);\n return db;\n }\n return null;\n },\n deps: [RXDB_OPTIONS, PLATFORM_ID]\n }\n ];\n};\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnhkYi5wcm92aWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3BhY2thZ2VzL3J4ZGItYW5ndWxhci9zcmMvcnhkYi5wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUFlLE1BQU0sWUFBWSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxXQUFXLEVBQVksTUFBTSxlQUFlLENBQUM7QUFDdEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRWhEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLENBQUMsT0FBb0IsRUFBRSxRQUE2QixFQUFjLEVBQUU7SUFDN0YsT0FBTztRQUNMO1lBQ0UsT0FBTyxFQUFFLFlBQVk7WUFDckIsUUFBUSxFQUFFLE9BQU87U0FDbEI7UUFDRDtZQUNFLE9BQU8sRUFBRSxJQUFJO1lBQ2IsVUFBVSxFQUFFLENBQUMsT0FBb0IsRUFBRSxVQUFlLEVBQUUsRUFBRTtnQkFDcEQsSUFBSSxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO29CQUNsQyxNQUFNLEVBQUUsR0FBRyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztvQkFDN0IsSUFBSSxRQUFRO3dCQUFFLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDM0IsT0FBTyxFQUFFLENBQUM7Z0JBQ1osQ0FBQztnQkFDRCxPQUFPLElBQUksQ0FBQztZQUNkLENBQUM7WUFDRCxJQUFJLEVBQUUsQ0FBQyxZQUFZLEVBQUUsV0FBVyxDQUFDO1NBQ2xDO0tBQ0YsQ0FBQztBQUNKLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJ4REIsIFJ4REJPcHRpb25zIH0gZnJvbSAnQGFpYW8vcnhkYic7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBQTEFURk9STV9JRCwgUHJvdmlkZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJYREJfT1BUSU9OUyB9IGZyb20gJy4vcnhkYi5pbnRlcmZhY2UnO1xuXG4vKipcbiAqIFJ4REIg6YWN572uXG4gKi9cbmV4cG9ydCBjb25zdCBwcm92aWRlUnhEQiA9IChvcHRpb25zOiBSeERCT3B0aW9ucywgY2FsbGJhY2s/OiAoZGI6IFJ4REIpID0+IHZvaWQpOiBQcm92aWRlcltdID0+IHtcbiAgcmV0dXJuIFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBSWERCX09QVElPTlMsXG4gICAgICB1c2VWYWx1ZTogb3B0aW9uc1xuICAgIH0sXG4gICAge1xuICAgICAgcHJvdmlkZTogUnhEQixcbiAgICAgIHVzZUZhY3Rvcnk6IChvcHRpb25zOiBSeERCT3B0aW9ucywgcGxhdGZvcm1JZDogYW55KSA9PiB7XG4gICAgICAgIGlmIChpc1BsYXRmb3JtQnJvd3NlcihwbGF0Zm9ybUlkKSkge1xuICAgICAgICAgIGNvbnN0IGRiID0gbmV3IFJ4REIob3B0aW9ucyk7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKSBjYWxsYmFjayhkYik7XG4gICAgICAgICAgcmV0dXJuIGRiO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfSxcbiAgICAgIGRlcHM6IFtSWERCX09QVElPTlMsIFBMQVRGT1JNX0lEXVxuICAgIH1cbiAgXTtcbn07XG4iXX0=","import { Injectable } from '@angular/core';\nimport * as i0 from \"@angular/core\";\nexport class RxDBService {\n static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: \"12.0.0\", version: \"20.1.7\", ngImport: i0, type: RxDBService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });\n static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: \"12.0.0\", version: \"20.1.7\", ngImport: i0, type: RxDBService, providedIn: 'root' });\n}\ni0.ɵɵngDeclareClassMetadata({ minVersion: \"12.0.0\", version: \"20.1.7\", ngImport: i0, type: RxDBService, decorators: [{\n type: Injectable,\n args: [{ providedIn: 'root' }]\n }] });\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnhkYi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcGFja2FnZXMvcnhkYi1hbmd1bGFyL3NyYy9yeGRiLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUFHM0MsTUFBTSxPQUFPLFdBQVc7dUdBQVgsV0FBVzsyR0FBWCxXQUFXLGNBREUsTUFBTTs7MkZBQ25CLFdBQVc7a0JBRHZCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFJ4REJTZXJ2aWNlIHt9XG4iXX0=","/**\n * Generated bundle index. Do not edit.\n */\nexport * from './index';\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWlhby1yeGRiLWFuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wYWNrYWdlcy9yeGRiLWFuZ3VsYXIvc3JjL2FpYW8tcnhkYi1hbmd1bGFyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19"],"names":[],"mappings":";;;;;AACO,MAAM,YAAY,GAAG,IAAI,cAAc,CAAC,cAAc,CAAC;;ACG9D;AACA;AACA;AACY,MAAC,WAAW,GAAG,CAAC,OAAO,EAAE,QAAQ,KAAK;AAClD,IAAI,OAAO;AACX,QAAQ;AACR,YAAY,OAAO,EAAE,YAAY;AACjC,YAAY,QAAQ,EAAE;AACtB,SAAS;AACT,QAAQ;AACR,YAAY,OAAO,EAAE,IAAI;AACzB,YAAY,UAAU,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK;AACjD,gBAAgB,IAAI,iBAAiB,CAAC,UAAU,CAAC,EAAE;AACnD,oBAAoB,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC;AAChD,oBAAoB,IAAI,QAAQ;AAChC,wBAAwB,QAAQ,CAAC,EAAE,CAAC;AACpC,oBAAoB,OAAO,EAAE;AAC7B,gBAAgB;AAChB,gBAAgB,OAAO,IAAI;AAC3B,YAAY,CAAC;AACb,YAAY,IAAI,EAAE,CAAC,YAAY,EAAE,WAAW;AAC5C;AACA,KAAK;AACL;;ACzBO,MAAM,WAAW,CAAC;AACzB,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC;AACtK,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAC7I;AACA,EAAE,CAAC,wBAAwB,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AACrH,YAAY,IAAI,EAAE,UAAU;AAC5B,YAAY,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE;AACzC,SAAS,CAAC,EAAE,CAAC;;ACTb;AACA;AACA;;;;"}
|
|
1
|
+
{"version":3,"file":"aiao-rxdb-angular.mjs","sources":["../../../../packages/rxdb-angular/src/hooks.ts","../../../../packages/rxdb-angular/src/InfiniteScrollingList.ts","../../../../packages/rxdb-angular/src/rxdb-change-detector.directive.ts","../../../../packages/rxdb-angular/src/rxdb.provider.ts","../../../../packages/rxdb-angular/src/use-action.ts","../../../../packages/rxdb-angular/src/use-state.ts","../../../../packages/rxdb-angular/src/aiao-rxdb-angular.ts"],"sourcesContent":["import { EntityStaticType, EntityType, TreeEntityType } from '@aiao/rxdb';\nimport { GraphEntityType } from '@aiao/rxdb-plugin-graph';\nimport { isFunction } from '@aiao/utils';\nimport { effect, Signal, signal } from '@angular/core';\nimport { toLazySignal } from 'ngxtension/to-lazy-signal';\nimport { Observable, Subscriber, Subscription } from 'rxjs';\n\ntype UseOptions<T> = T | (() => T);\n\nexport interface RxDBResource<T> {\n /**\n * 资源的值\n */\n readonly value: Signal<T>;\n /**\n * 资源的错误\n */\n readonly error: Signal<Error | undefined>;\n /**\n * 资源的加载状态\n */\n readonly isLoading: Signal<boolean>;\n /**\n * 资源是否为空\n */\n readonly isEmpty: Signal<boolean | undefined>;\n /**\n * 资源是否有值\n */\n readonly hasValue: Signal<boolean>;\n}\n\nexport const useRepositoryQuery = <T extends EntityType, RT>(\n EntityType: T,\n method: string,\n defaultValue: any,\n options: UseOptions<any>\n): RxDBResource<RT> => {\n let _observer: Subscriber<any>;\n let sub: Subscription;\n\n const _has_sub = signal<boolean>(false);\n const _refresh = signal<number>(0);\n\n const _eff = effect(() => {\n if (_has_sub() === false) return;\n // re-run when refresh is called or options change\n _refresh();\n const opt = isFunction(options) ? options() : options;\n if (sub) sub.unsubscribe();\n // reset state for a new request\n isLoading.set(true);\n error.set(undefined);\n hasValue.set(false);\n isEmpty.set(undefined);\n // 优化:使用 Record<string, any> 替代 any,以提高类型安全性\n const func = (EntityType as unknown as Record<string, any>)[method];\n sub =\n func &&\n func(opt).subscribe({\n next: (d: any) => {\n isLoading.set(false);\n hasValue.set(true);\n if (Array.isArray(d)) {\n isEmpty.set(d.length === 0);\n } else if (d == null) {\n // null/undefined treated as empty\n isEmpty.set(true);\n } else {\n isEmpty.set(false);\n }\n _observer.next(d);\n },\n error: (e: any) => {\n isLoading.set(false);\n error.set(e);\n },\n complete: () => {\n // ensure loading is false even if observable completes without next\n isLoading.set(false);\n }\n });\n });\n const ob = new Observable<RT>(observer => {\n _has_sub.set(true);\n _observer = observer;\n _observer.next(defaultValue);\n return () => {\n _eff.destroy();\n sub?.unsubscribe();\n };\n });\n\n const value = toLazySignal<RT>(ob, {\n initialValue: defaultValue\n }) as Signal<RT>;\n const error = signal<Error | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n const hasValue = signal<boolean>(false);\n const isEmpty = signal<boolean | undefined>(undefined);\n return {\n value,\n error,\n isLoading,\n isEmpty,\n hasValue\n };\n};\n\n/*\n * Repository\n */\n\n/**\n * 通过 ID 获取单个实体\n *\n * @param EntityType 实体类\n * @param options 实体 ID 或查询参数对象\n * @returns 返回包含实体的资源 signal\n *\n * @example\n * ```typescript\n * const user = useGet(User, 'user-1');\n * ```\n */\nexport const useGet = <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, 'getOptions'>>) =>\n useRepositoryQuery<T, InstanceType<T>>(EntityType, 'get', undefined, options);\n\n/**\n * 查找第一个匹配条件的实体\n *\n * @param EntityType 实体类\n * @param options 查询参数(where、排序等)\n * @returns 返回包含实体的资源 signal\n */\nexport const useFindOne = <T extends EntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findOneOptions'>>\n) => useRepositoryQuery<T, InstanceType<T> | undefined>(EntityType, 'findOne', undefined, options);\n\n/**\n * 查找匹配的实体,未找到则抛出错误\n *\n * @param EntityType 实体类\n * @param options 查询参数\n * @returns 返回包含实体的资源 signal\n */\nexport const useFindOneOrFail = <T extends EntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findOneOrFailOptions'>>\n) => useRepositoryQuery<T, InstanceType<T>>(EntityType, 'findOneOrFail', undefined, options);\n\n/**\n * 查找符合条件的多个实体\n *\n * @param EntityType 实体类\n * @param options 查询参数\n * @returns 返回包含实体数组的资源 signal\n */\nexport const useFind = <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, 'findOptions'>>) =>\n useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'find', [], options);\n\n/**\n * 使用游标分页查找实体\n *\n * @param EntityType 实体类\n * @param options 游标参数\n * @returns 返回包含实体数组的资源 signal\n */\nexport const useFindByCursor = <T extends EntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findByCursorOptions'>>\n) => useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findByCursor', [], options);\n\n/**\n * 查找全部实体\n *\n * @param EntityType 实体类\n * @param options 查询参数\n * @returns 返回包含全部实体的资源 signal\n */\nexport const useFindAll = <T extends EntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findAllOptions'>>\n) => useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findAll', [], options);\n\n/**\n * 统计满足条件的实体数量\n *\n * @param EntityType 实体类\n * @param options 查询参数\n * @returns 返回包含数量的资源 signal\n */\nexport const useCount = <T extends EntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'countOptions'>>\n) => useRepositoryQuery<T, number>(EntityType, 'count', undefined, options);\n\n/*\n * TreeRepository\n */\n\n/**\n * 查找树结构中的所有子孙实体\n *\n * @param EntityType 实体类\n * @param options 树查询参数(entityId、深度等)\n * @returns 返回包含子孙实体的资源 signal\n */\nexport const useFindDescendants = <T extends TreeEntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>\n) => useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findDescendants', [], options);\n\n/**\n * 统计树结构中的子孙数量\n *\n * @param EntityType 实体类\n * @param options 树查询参数\n * @returns 返回包含数量的资源 signal\n */\nexport const useCountDescendants = <T extends TreeEntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>\n) => useRepositoryQuery<T, number>(EntityType, 'countDescendants', undefined, options);\n\n/**\n * 查找树结构中的所有祖先实体\n *\n * @param EntityType 实体类\n * @param options 树查询参数\n * @returns 返回包含祖先实体的资源 signal\n */\nexport const useFindAncestors = <T extends TreeEntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>\n) => useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findAncestors', [], options);\n\n/**\n * 统计树结构中的祖先数量\n *\n * @param EntityType 实体类\n * @param options 树查询参数\n * @returns 返回包含数量的资源 signal\n */\nexport const useCountAncestors = <T extends TreeEntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findTreeOptions'>>\n) => useRepositoryQuery<T, number>(EntityType, 'countAncestors', undefined, options);\n\n/*\n * GraphRepository\n */\n\n/**\n * 查找图结构中的邻接实体\n *\n * @param EntityType 实体类\n * @param options 图查询参数(entityId、方向、层级等)\n * @returns 返回包含邻居实体的资源 signal\n *\n * @example\n * ```typescript\n * const friends = useGraphNeighbors(User, {\n * entityId: 'user-1',\n * direction: 'out',\n * level: 1\n * });\n * ```\n */\nexport const useGraphNeighbors = <T extends GraphEntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findNeighborsOptions'>>\n) => useRepositoryQuery<T, InstanceType<T>[]>(EntityType, 'findNeighbors', [], options);\n\n/**\n * 统计图结构中的邻接数量\n *\n * @param EntityType 实体类\n * @param options 图查询参数\n * @returns 返回包含数量的资源 signal\n */\nexport const useCountNeighbors = <T extends GraphEntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findNeighborsOptions'>>\n) => useRepositoryQuery<T, number>(EntityType, 'countNeighbors', 0, options);\n\n/**\n * 查找图结构中两个实体之间的路径\n *\n * @param EntityType 实体类\n * @param options 路径查询参数(fromId、toId、最大深度等)\n * @returns 返回包含路径的资源 signal\n *\n * @example\n * ```typescript\n * const paths = useGraphPaths(User, {\n * fromId: 'user-1',\n * toId: 'user-2',\n * maxDepth: 5\n * });\n * ```\n */\nexport const useGraphPaths = <T extends GraphEntityType>(\n EntityType: T,\n options: UseOptions<EntityStaticType<T, 'findPathsOptions'>>\n) => useRepositoryQuery<T, any[]>(EntityType, 'findPaths', [], options);\n","import { EntityType, FindByCursorOptions, RxDB } from '@aiao/rxdb';\nimport { isFunction, nextMicroTask } from '@aiao/utils';\nimport { computed, DestroyRef, effect, EffectRef, inject, Signal, signal, untracked } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\ntype OptionsInput<T extends EntityType> = FindByCursorOptions<T> | Signal<FindByCursorOptions<T>>;\n\n/**\n * 无限滚动的列表\n */\nexport class InfiniteScrollingList<T extends EntityType> {\n readonly #values = signal<InstanceType<T>[][]>([]);\n readonly #destroy_ref = inject(DestroyRef);\n readonly #options_eff: EffectRef;\n\n #is_initialized = false;\n\n readonly error = signal<Error | undefined>(undefined);\n readonly isLoading = signal<boolean>(false);\n readonly hasMore = signal<boolean>(true);\n readonly value = computed<InstanceType<T>[]>(() => this.#values().flat());\n readonly hasValue = computed<boolean>(() => this.value().length > 0);\n readonly isEmpty = computed<boolean>(() => !this.isLoading() && !this.hasValue() && this.#is_initialized);\n\n constructor(\n private readonly rxdb: RxDB,\n private readonly EntityType: T,\n private readonly options: OptionsInput<T>\n ) {\n this.#options_eff = effect(() => {\n if (isFunction(this.options)) {\n this.options();\n }\n if (!this.#is_initialized) {\n this.#is_initialized = true;\n nextMicroTask(() => this.loadMore());\n return;\n }\n untracked(() => this.#reset());\n });\n\n this.#destroy_ref.onDestroy(() => {\n this.#options_eff.destroy();\n });\n }\n\n loadMore(): void {\n if (this.isLoading() || !this.hasMore()) {\n return;\n }\n\n this.isLoading.set(true);\n this.error.set(undefined);\n\n const last_entity = this.#get_last_entity();\n const opt = isFunction(this.options) ? this.options() : this.options;\n const options = structuredClone(opt);\n\n if (last_entity) {\n options.after = last_entity;\n }\n\n const current_index = this.#values().length;\n\n this.rxdb.entityManager\n .getRepository(this.EntityType)\n .findByCursor(options)\n .pipe(takeUntilDestroyed(this.#destroy_ref))\n .subscribe({\n next: result => {\n this.isLoading.set(false);\n this.#values.update(values => {\n const updated = [...values];\n updated[current_index] = result;\n return updated;\n });\n\n if (result.length < (options.limit || 100)) {\n this.hasMore.set(false);\n }\n },\n error: error => {\n this.isLoading.set(false);\n this.error.set(error);\n },\n complete: () => {\n this.hasMore.set(false);\n this.isLoading.set(false);\n }\n });\n }\n\n /**\n * 刷新列表数据\n */\n refresh(): void {\n // 强制重置状态,即使正在加载中\n this.#values.set([]);\n this.error.set(undefined);\n this.isLoading.set(false); // 强制设置为 false,允许新的 loadMore\n this.hasMore.set(true);\n\n // 立即开始加载\n this.loadMore();\n }\n #reset(): void {\n this.#values.set([]);\n this.error.set(undefined);\n this.isLoading.set(false);\n this.hasMore.set(true);\n nextMicroTask(() => this.loadMore());\n }\n\n #get_last_entity(): InstanceType<T> | undefined {\n const values = this.#values();\n if (values.length === 0) return undefined;\n\n const last_page = values[values.length - 1];\n if (last_page.length === 0) return undefined;\n\n return last_page[last_page.length - 1];\n }\n}\n","import { EntityType, getEntityStatus } from '@aiao/rxdb';\nimport { ChangeDetectorRef, DestroyRef, Directive, effect, inject, input } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { auditTime, debounceTime, Subscription } from 'rxjs';\n\n/**\n * RxDB 实体变化指令\n * 如果你使用了 `changeDetection: ChangeDetectionStrategy.OnPush`\n * 那么正在输入的变化不会触发 angular 渲染机制,使用这个指令可以实现实时渲染\n *\n * @example\n * 当修改实体时,需要在多个地方预览修改变化时,可以使用这个指令\n */\n@Directive({ selector: '[rxdbChangeDetector]' })\nexport class RxDBEntityChangeDirective {\n #destroyRef = inject(DestroyRef);\n #changeDetectorRef = inject(ChangeDetectorRef);\n #sub?: Subscription;\n public readonly rxdbChangeDetector = input<InstanceType<EntityType>>();\n public readonly debounceTime = input<number>(0);\n public readonly auditTime = input<number>(0);\n\n constructor() {\n effect(() => {\n const rxdbChange = this.rxdbChangeDetector();\n const dt = this.debounceTime();\n const at = this.auditTime();\n const status = getEntityStatus(rxdbChange);\n this.#sub?.unsubscribe();\n this.#sub = status.patches$\n .pipe(takeUntilDestroyed(this.#destroyRef), debounceTime(dt), auditTime(at))\n .subscribe(() => this.#changeDetectorRef.markForCheck());\n });\n }\n}\n","import { RxDB } from '@aiao/rxdb';\nimport { makeEnvironmentProviders } from '@angular/core';\n\n/**\n * RxDB 配置\n */\nexport const provideRxDB = (useFactory?: () => RxDB) =>\n makeEnvironmentProviders([\n {\n provide: RxDB,\n useFactory\n }\n ]);\n","import { signal } from '@angular/core';\n\nconst action = <Options = any, RT = any>(promiseFn: (options?: Options) => Promise<RT>) => {\n const isPending = signal<boolean>(false);\n return {\n isPending,\n execute: async (options?: Options) => {\n isPending.set(true);\n try {\n const d = await promiseFn(options);\n return d;\n } finally {\n isPending.set(false);\n }\n }\n };\n};\n\nexport const useAction = <Options = any, RT = any>(promiseFn: (options?: Options) => Promise<RT>) =>\n action<Options, RT>(promiseFn);\n","import { IS_BROWSER } from '@aiao/utils';\nimport { CreateSignalOptions, effect, signal as ngSignal, WritableSignal } from '@angular/core';\n\nfunction state(namespace: string) {\n return (name: string) => {\n const signal = <T>(initialValue: T, options?: CreateSignalOptions<T>): WritableSignal<T> => {\n if (IS_BROWSER) {\n const value = localStorage.getItem(`${namespace}:${name}`);\n if (value) {\n initialValue = JSON.parse(value);\n }\n }\n const a = ngSignal<T>(initialValue, options);\n effect(() => {\n if (IS_BROWSER) {\n localStorage.setItem(`${namespace}:${name}`, JSON.stringify(a()));\n }\n });\n return a;\n };\n\n return {\n signal\n };\n };\n}\n\nexport const useState = (namespace: string) => state(namespace);\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["signal","ngSignal"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiao/rxdb-angular",
|
|
3
|
-
"version": "0.0.3",
|
|
4
3
|
"peerDependencies": {
|
|
5
|
-
"@aiao/rxdb": "0.0.
|
|
6
|
-
"@
|
|
7
|
-
"@
|
|
4
|
+
"@aiao/rxdb": "^0.0.8",
|
|
5
|
+
"@aiao/rxdb-plugin-graph": "^0.0.8",
|
|
6
|
+
"@aiao/utils": "^0.0.8",
|
|
7
|
+
"@angular/core": ">=20.0.0",
|
|
8
|
+
"ngxtension": "^7.0.1",
|
|
9
|
+
"rxjs": "^7.8.2"
|
|
8
10
|
},
|
|
9
|
-
"sideEffects": false,
|
|
10
11
|
"publishConfig": {
|
|
11
12
|
"access": "public"
|
|
12
13
|
},
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"version": "0.0.8",
|
|
13
16
|
"module": "fesm2022/aiao-rxdb-angular.mjs",
|
|
14
|
-
"typings": "
|
|
17
|
+
"typings": "types/aiao-rxdb-angular.d.ts",
|
|
15
18
|
"exports": {
|
|
16
19
|
"./package.json": {
|
|
17
20
|
"default": "./package.json"
|
|
18
21
|
},
|
|
19
22
|
".": {
|
|
20
|
-
"types": "./
|
|
23
|
+
"types": "./types/aiao-rxdb-angular.d.ts",
|
|
21
24
|
"default": "./fesm2022/aiao-rxdb-angular.mjs"
|
|
22
25
|
}
|
|
23
26
|
},
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { EntityType, EntityStaticType, TreeEntityType, RxDB, FindByCursorOptions } from '@aiao/rxdb';
|
|
2
|
+
import { GraphEntityType } from '@aiao/rxdb-plugin-graph';
|
|
3
|
+
import * as _angular_core from '@angular/core';
|
|
4
|
+
import { Signal, CreateSignalOptions, WritableSignal } from '@angular/core';
|
|
5
|
+
|
|
6
|
+
type UseOptions<T> = T | (() => T);
|
|
7
|
+
interface RxDBResource<T> {
|
|
8
|
+
/**
|
|
9
|
+
* 资源的值
|
|
10
|
+
*/
|
|
11
|
+
readonly value: Signal<T>;
|
|
12
|
+
/**
|
|
13
|
+
* 资源的错误
|
|
14
|
+
*/
|
|
15
|
+
readonly error: Signal<Error | undefined>;
|
|
16
|
+
/**
|
|
17
|
+
* 资源的加载状态
|
|
18
|
+
*/
|
|
19
|
+
readonly isLoading: Signal<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* 资源是否为空
|
|
22
|
+
*/
|
|
23
|
+
readonly isEmpty: Signal<boolean | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* 资源是否有值
|
|
26
|
+
*/
|
|
27
|
+
readonly hasValue: Signal<boolean>;
|
|
28
|
+
}
|
|
29
|
+
declare const useRepositoryQuery: <T extends EntityType, RT>(EntityType: T, method: string, defaultValue: any, options: UseOptions<any>) => RxDBResource<RT>;
|
|
30
|
+
/**
|
|
31
|
+
* 通过 ID 获取单个实体
|
|
32
|
+
*
|
|
33
|
+
* @param EntityType 实体类
|
|
34
|
+
* @param options 实体 ID 或查询参数对象
|
|
35
|
+
* @returns 返回包含实体的资源 signal
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const user = useGet(User, 'user-1');
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare const useGet: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "getOptions">>) => RxDBResource<InstanceType<T>>;
|
|
43
|
+
/**
|
|
44
|
+
* 查找第一个匹配条件的实体
|
|
45
|
+
*
|
|
46
|
+
* @param EntityType 实体类
|
|
47
|
+
* @param options 查询参数(where、排序等)
|
|
48
|
+
* @returns 返回包含实体的资源 signal
|
|
49
|
+
*/
|
|
50
|
+
declare const useFindOne: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findOneOptions">>) => RxDBResource<InstanceType<T> | undefined>;
|
|
51
|
+
/**
|
|
52
|
+
* 查找匹配的实体,未找到则抛出错误
|
|
53
|
+
*
|
|
54
|
+
* @param EntityType 实体类
|
|
55
|
+
* @param options 查询参数
|
|
56
|
+
* @returns 返回包含实体的资源 signal
|
|
57
|
+
*/
|
|
58
|
+
declare const useFindOneOrFail: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findOneOrFailOptions">>) => RxDBResource<InstanceType<T>>;
|
|
59
|
+
/**
|
|
60
|
+
* 查找符合条件的多个实体
|
|
61
|
+
*
|
|
62
|
+
* @param EntityType 实体类
|
|
63
|
+
* @param options 查询参数
|
|
64
|
+
* @returns 返回包含实体数组的资源 signal
|
|
65
|
+
*/
|
|
66
|
+
declare const useFind: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findOptions">>) => RxDBResource<InstanceType<T>[]>;
|
|
67
|
+
/**
|
|
68
|
+
* 使用游标分页查找实体
|
|
69
|
+
*
|
|
70
|
+
* @param EntityType 实体类
|
|
71
|
+
* @param options 游标参数
|
|
72
|
+
* @returns 返回包含实体数组的资源 signal
|
|
73
|
+
*/
|
|
74
|
+
declare const useFindByCursor: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findByCursorOptions">>) => RxDBResource<InstanceType<T>[]>;
|
|
75
|
+
/**
|
|
76
|
+
* 查找全部实体
|
|
77
|
+
*
|
|
78
|
+
* @param EntityType 实体类
|
|
79
|
+
* @param options 查询参数
|
|
80
|
+
* @returns 返回包含全部实体的资源 signal
|
|
81
|
+
*/
|
|
82
|
+
declare const useFindAll: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findAllOptions">>) => RxDBResource<InstanceType<T>[]>;
|
|
83
|
+
/**
|
|
84
|
+
* 统计满足条件的实体数量
|
|
85
|
+
*
|
|
86
|
+
* @param EntityType 实体类
|
|
87
|
+
* @param options 查询参数
|
|
88
|
+
* @returns 返回包含数量的资源 signal
|
|
89
|
+
*/
|
|
90
|
+
declare const useCount: <T extends EntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "countOptions">>) => RxDBResource<number>;
|
|
91
|
+
/**
|
|
92
|
+
* 查找树结构中的所有子孙实体
|
|
93
|
+
*
|
|
94
|
+
* @param EntityType 实体类
|
|
95
|
+
* @param options 树查询参数(entityId、深度等)
|
|
96
|
+
* @returns 返回包含子孙实体的资源 signal
|
|
97
|
+
*/
|
|
98
|
+
declare const useFindDescendants: <T extends TreeEntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<InstanceType<T>[]>;
|
|
99
|
+
/**
|
|
100
|
+
* 统计树结构中的子孙数量
|
|
101
|
+
*
|
|
102
|
+
* @param EntityType 实体类
|
|
103
|
+
* @param options 树查询参数
|
|
104
|
+
* @returns 返回包含数量的资源 signal
|
|
105
|
+
*/
|
|
106
|
+
declare const useCountDescendants: <T extends TreeEntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<number>;
|
|
107
|
+
/**
|
|
108
|
+
* 查找树结构中的所有祖先实体
|
|
109
|
+
*
|
|
110
|
+
* @param EntityType 实体类
|
|
111
|
+
* @param options 树查询参数
|
|
112
|
+
* @returns 返回包含祖先实体的资源 signal
|
|
113
|
+
*/
|
|
114
|
+
declare const useFindAncestors: <T extends TreeEntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<InstanceType<T>[]>;
|
|
115
|
+
/**
|
|
116
|
+
* 统计树结构中的祖先数量
|
|
117
|
+
*
|
|
118
|
+
* @param EntityType 实体类
|
|
119
|
+
* @param options 树查询参数
|
|
120
|
+
* @returns 返回包含数量的资源 signal
|
|
121
|
+
*/
|
|
122
|
+
declare const useCountAncestors: <T extends TreeEntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findTreeOptions">>) => RxDBResource<number>;
|
|
123
|
+
/**
|
|
124
|
+
* 查找图结构中的邻接实体
|
|
125
|
+
*
|
|
126
|
+
* @param EntityType 实体类
|
|
127
|
+
* @param options 图查询参数(entityId、方向、层级等)
|
|
128
|
+
* @returns 返回包含邻居实体的资源 signal
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const friends = useGraphNeighbors(User, {
|
|
133
|
+
* entityId: 'user-1',
|
|
134
|
+
* direction: 'out',
|
|
135
|
+
* level: 1
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
declare const useGraphNeighbors: <T extends GraphEntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findNeighborsOptions">>) => RxDBResource<InstanceType<T>[]>;
|
|
140
|
+
/**
|
|
141
|
+
* 统计图结构中的邻接数量
|
|
142
|
+
*
|
|
143
|
+
* @param EntityType 实体类
|
|
144
|
+
* @param options 图查询参数
|
|
145
|
+
* @returns 返回包含数量的资源 signal
|
|
146
|
+
*/
|
|
147
|
+
declare const useCountNeighbors: <T extends GraphEntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findNeighborsOptions">>) => RxDBResource<number>;
|
|
148
|
+
/**
|
|
149
|
+
* 查找图结构中两个实体之间的路径
|
|
150
|
+
*
|
|
151
|
+
* @param EntityType 实体类
|
|
152
|
+
* @param options 路径查询参数(fromId、toId、最大深度等)
|
|
153
|
+
* @returns 返回包含路径的资源 signal
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const paths = useGraphPaths(User, {
|
|
158
|
+
* fromId: 'user-1',
|
|
159
|
+
* toId: 'user-2',
|
|
160
|
+
* maxDepth: 5
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare const useGraphPaths: <T extends GraphEntityType>(EntityType: T, options: UseOptions<EntityStaticType<T, "findPathsOptions">>) => RxDBResource<any[]>;
|
|
165
|
+
|
|
166
|
+
type OptionsInput<T extends EntityType> = FindByCursorOptions<T> | Signal<FindByCursorOptions<T>>;
|
|
167
|
+
/**
|
|
168
|
+
* 无限滚动的列表
|
|
169
|
+
*/
|
|
170
|
+
declare class InfiniteScrollingList<T extends EntityType> {
|
|
171
|
+
#private;
|
|
172
|
+
private readonly rxdb;
|
|
173
|
+
private readonly EntityType;
|
|
174
|
+
private readonly options;
|
|
175
|
+
readonly error: _angular_core.WritableSignal<Error | undefined>;
|
|
176
|
+
readonly isLoading: _angular_core.WritableSignal<boolean>;
|
|
177
|
+
readonly hasMore: _angular_core.WritableSignal<boolean>;
|
|
178
|
+
readonly value: Signal<InstanceType<T>[]>;
|
|
179
|
+
readonly hasValue: Signal<boolean>;
|
|
180
|
+
readonly isEmpty: Signal<boolean>;
|
|
181
|
+
constructor(rxdb: RxDB, EntityType: T, options: OptionsInput<T>);
|
|
182
|
+
loadMore(): void;
|
|
183
|
+
/**
|
|
184
|
+
* 刷新列表数据
|
|
185
|
+
*/
|
|
186
|
+
refresh(): void;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* RxDB 实体变化指令
|
|
191
|
+
* 如果你使用了 `changeDetection: ChangeDetectionStrategy.OnPush`
|
|
192
|
+
* 那么正在输入的变化不会触发 angular 渲染机制,使用这个指令可以实现实时渲染
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* 当修改实体时,需要在多个地方预览修改变化时,可以使用这个指令
|
|
196
|
+
*/
|
|
197
|
+
declare class RxDBEntityChangeDirective {
|
|
198
|
+
#private;
|
|
199
|
+
readonly rxdbChangeDetector: _angular_core.InputSignal<any>;
|
|
200
|
+
readonly debounceTime: _angular_core.InputSignal<number>;
|
|
201
|
+
readonly auditTime: _angular_core.InputSignal<number>;
|
|
202
|
+
constructor();
|
|
203
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<RxDBEntityChangeDirective, never>;
|
|
204
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RxDBEntityChangeDirective, "[rxdbChangeDetector]", never, { "rxdbChangeDetector": { "alias": "rxdbChangeDetector"; "required": false; "isSignal": true; }; "debounceTime": { "alias": "debounceTime"; "required": false; "isSignal": true; }; "auditTime": { "alias": "auditTime"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* RxDB 配置
|
|
209
|
+
*/
|
|
210
|
+
declare const provideRxDB: (useFactory?: () => RxDB) => _angular_core.EnvironmentProviders;
|
|
211
|
+
|
|
212
|
+
declare const useAction: <Options = any, RT = any>(promiseFn: (options?: Options) => Promise<RT>) => {
|
|
213
|
+
isPending: _angular_core.WritableSignal<boolean>;
|
|
214
|
+
execute: (options?: Options | undefined) => Promise<RT>;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
declare const useState: (namespace: string) => (name: string) => {
|
|
218
|
+
signal: <T>(initialValue: T, options?: CreateSignalOptions<T>) => WritableSignal<T>;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export { InfiniteScrollingList, RxDBEntityChangeDirective, provideRxDB, useAction, useCount, useCountAncestors, useCountDescendants, useCountNeighbors, useFind, useFindAll, useFindAncestors, useFindByCursor, useFindDescendants, useFindOne, useFindOneOrFail, useGet, useGraphNeighbors, useGraphPaths, useRepositoryQuery, useState };
|
|
222
|
+
export type { RxDBResource };
|
package/index.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { RxDBOptions, RxDB } from '@aiao/rxdb';
|
|
2
|
-
import * as i0 from '@angular/core';
|
|
3
|
-
import { Provider } from '@angular/core';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* RxDB 配置
|
|
7
|
-
*/
|
|
8
|
-
declare const provideRxDB: (options: RxDBOptions, callback?: (db: RxDB) => void) => Provider[];
|
|
9
|
-
|
|
10
|
-
declare class RxDBService {
|
|
11
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<RxDBService, never>;
|
|
12
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<RxDBService>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export { RxDBService, provideRxDB };
|