T
TanStack6d ago
frail-apricot

type signature for query builder instance?

I'm wondering what's the correct pattern here -- I'd like to have a function that applies a bunch of filters to any given query that selects a certain type of collection. for instance
const someFancyFilteringFunctionThatWillBeReused = <
T extends QueryBuilder<unknown>
>(
query: T
): T => {
return query.where(({ item }) => eq(item.active, true));
};

const { data } = useLiveQuery((q) => {
let query = q
.from({ item: itemCollection })
.where(({ item }) => and(eq(item.id, 1)));

query = someFancyFilteringFunctionThatWillBeReused(query);

return query.select(({ item }) => ({
...item,
}));
}, []);

data.map((item) => item.active); // item with id 1 and active true
const someFancyFilteringFunctionThatWillBeReused = <
T extends QueryBuilder<unknown>
>(
query: T
): T => {
return query.where(({ item }) => eq(item.active, true));
};

const { data } = useLiveQuery((q) => {
let query = q
.from({ item: itemCollection })
.where(({ item }) => and(eq(item.id, 1)));

query = someFancyFilteringFunctionThatWillBeReused(query);

return query.select(({ item }) => ({
...item,
}));
}, []);

data.map((item) => item.active); // item with id 1 and active true
I'd like to know if there's an approach to type that object properly. I can alternatively see the approach of just having a hook that does return a pre-applied query, but I'd like to explore the other option first. thanks!
2 Replies
foreign-sapphire
foreign-sapphire5d ago
here's a PR with some improvements to the docs — great question! https://github.com/TanStack/db/pull/882
GitHub
Improve documentation for creating reusable filter functions by Kyl...
Add comprehensive guide for creating reusable filter callbacks Explain why typing QueryBuilder directly is not recommended Add examples for chaining filters, using different aliases, and multi-tabl...
frail-apricot
frail-apricotOP5d ago
oh you're the goat Kyle! here I was trying to extract the returntype of BaseQuery.from
from<TSource extends Source>(source: TSource): QueryBuilder<{
baseSchema: SchemaFromSource<TSource>;
schema: SchemaFromSource<TSource>;
fromSourceName: keyof TSource & string;
hasJoins: false;
}>;
from<TSource extends Source>(source: TSource): QueryBuilder<{
baseSchema: SchemaFromSource<TSource>;
schema: SchemaFromSource<TSource>;
fromSourceName: keyof TSource & string;
hasJoins: false;
}>;
that approach makes sense, thanks!

Did you find this page helpful?