rxdb
Version:
A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/
169 lines (153 loc) • 4.43 kB
text/typescript
import { useCallback, useEffect, useState } from 'react';
import type {
MangoQuery,
RxCollection,
RxDocument,
} from '../../../types/index.d.ts';
import { isRxCollection } from '../../../rx-collection.ts';
import { useRxCollection } from './use-rx-collection.ts';
import { newRxError } from '../../../rx-error.ts';
export type UseRxQueryOptions<
RxDocumentType = any,
OrmMethods = {},
StaticMethods = {},
InstanceCreationOptions = {},
Reactivity = unknown,
> = {
collection:
| string
| RxCollection<
RxDocumentType,
OrmMethods,
StaticMethods,
InstanceCreationOptions,
Reactivity
>;
query: MangoQuery<RxDocumentType>;
};
export type UseRxQueryResult<RxDocumentType = any, OrmMethods = {}> = {
results: RxDocument<RxDocumentType, OrmMethods>[];
loading: boolean;
error: string | null;
};
/**
* React hook to query an RxDB collection with Mango queries.
*
* @param {UseRxQueryOptions<RxDocumentType, OrmMethods, StaticMethods, InstanceCreationOptions, Reactivity>} options - Options for the query.
* @param {string|RxCollection} options.collection - The collection name or instance to query.
* @param {MangoQuery<RxDocumentType>} options.query - The Mango query to execute.
* @param {boolean} [options.live] - Whether to subscribe to live query updates.
*
* @returns {UseRxQueryResult<RxDocumentType, OrmMethods>} The query result, loading state, and error.
*/
export function useRxQueryBase<
RxDocumentType = any,
OrmMethods = {},
StaticMethods = {},
InstanceCreationOptions = {},
Reactivity = unknown,
>({
collection,
query,
live,
}: UseRxQueryOptions<
RxDocumentType,
OrmMethods,
StaticMethods,
InstanceCreationOptions,
Reactivity
> & { live: boolean }): UseRxQueryResult<RxDocumentType, OrmMethods> {
const [results, setResults] = useState(
[] as RxDocument<RxDocumentType, OrmMethods>[],
);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
let dbCollection: RxCollection<
RxDocumentType,
OrmMethods,
StaticMethods,
InstanceCreationOptions,
Reactivity
> | null;
if (typeof collection === 'string') {
dbCollection = useRxCollection<
RxDocumentType,
OrmMethods,
StaticMethods,
InstanceCreationOptions,
Reactivity
>(collection);
} else {
if (!isRxCollection(collection)) {
throw newRxError('R3', {
collection
});
}
dbCollection = collection;
}
(window as any).collection = dbCollection;
const emitResults = (res: RxDocument<RxDocumentType, OrmMethods>[]) => {
setResults(res);
if (loading) {
setLoading(false);
}
};
const emitError = (e: Error) => {
setError(e.message);
if (loading) {
setLoading(false);
}
};
const runQuery = useCallback(async () => {
if (dbCollection == null) {
return;
}
setError(null);
setLoading(loading);
const rxQuery = dbCollection.find(query);
if (live) {
const subscription = rxQuery.$.subscribe({
next: (res: RxDocument<RxDocumentType, OrmMethods>[]) => emitResults(res),
error: (err: Error) => emitError(err),
});
return () => {
subscription.unsubscribe();
};
} else {
try {
emitResults(await rxQuery.exec());
} catch (e) {
emitError(e as Error);
}
}
}, [dbCollection, query]);
useEffect(() => {
if (collection == null) {
return;
}
runQuery();
}, [runQuery]);
return { results, loading, error };
}
export function useRxQuery<
RxDocumentType = any,
OrmMethods = {},
StaticMethods = {},
InstanceCreationOptions = {},
Reactivity = unknown,
>({
collection,
query,
}: UseRxQueryOptions<
RxDocumentType,
OrmMethods,
StaticMethods,
InstanceCreationOptions,
Reactivity
>): UseRxQueryResult<RxDocumentType, OrmMethods> {
return useRxQueryBase({
collection,
query,
live: false
});
}