Skip to content

Commit

Permalink
Update queries
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-jeremy committed Oct 14, 2024
1 parent 2fe41da commit 13d8a9e
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 237 deletions.
20 changes: 11 additions & 9 deletions packages/desktop-client/src/components/accounts/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { type UndoState } from 'loot-core/server/undo';
import { useFilters } from 'loot-core/src/client/data-hooks/filters';
import {
SchedulesProvider,
useDefaultSchedulesQueryBuilder,
defaultSchedulesQueryBuilder,
} from 'loot-core/src/client/data-hooks/schedules';
import * as queries from 'loot-core/src/client/queries';
import {
Expand Down Expand Up @@ -215,7 +215,7 @@ function AllTransactions({
return balances;
}, [filtered, prependBalances, balances]);

if (!prependTransactions) {
if (!prependTransactions?.length || filtered) {
return children(transactions, balances);
}
return children(allTransactions, allBalances);
Expand Down Expand Up @@ -457,7 +457,7 @@ class AccountInternal extends PureComponent<
}

fetchAllIds = async () => {
const { data } = await runQuery(this.paged?.getQuery().select('id'));
const { data } = await runQuery(this.paged?.query.select('id'));
// Remember, this is the `grouped` split type so we need to deal
// with the `subtransactions` property
return data.reduce((arr: string[], t: TransactionEntity) => {
Expand Down Expand Up @@ -527,7 +527,7 @@ class AccountInternal extends PureComponent<
this.setState(
{
transactions: data,
transactionCount: this.paged?.getTotalCount(),
transactionCount: this.paged?.totalCount,
transactionsFiltered: isFiltered,
loading: false,
workingHard: false,
Expand Down Expand Up @@ -685,8 +685,7 @@ class AccountInternal extends PureComponent<
}

const { data } = await runQuery(
this.paged
?.getQuery()
this.paged?.query
.options({ splits: 'none' })
.select([{ balance: { $sumOver: '$amount' } }]),
);
Expand Down Expand Up @@ -857,7 +856,7 @@ class AccountInternal extends PureComponent<

getFilteredAmount = async () => {
const { data: amount } = await runQuery(
this.paged?.getQuery().calculate({ $sum: '$amount' }),
this.paged?.query.calculate({ $sum: '$amount' }),
);
return amount;
};
Expand Down Expand Up @@ -1879,10 +1878,13 @@ export function Account() {
const savedFiters = useFilters();
const actionCreators = useActions();

const queryBuilder = useDefaultSchedulesQueryBuilder(params.id);
const schedulesQueryBuilder = useMemo(
() => defaultSchedulesQueryBuilder(params.id),
[params.id],
);

return (
<SchedulesProvider queryBuilder={queryBuilder}>
<SchedulesProvider queryBuilder={schedulesQueryBuilder}>
<SplitsExpandedProvider
initialMode={expandSplits ? 'collapse' : 'expand'}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ import {
syncAndDownload,
updateAccount,
} from 'loot-core/client/actions';
import { useDefaultSchedulesQueryBuilder } from 'loot-core/client/data-hooks/schedules';
import { useTransactions } from 'loot-core/client/data-hooks/transactions';
import {
defaultSchedulesQueryBuilder,
SchedulesProvider,
} from 'loot-core/client/data-hooks/schedules';
import {
usePreviewTransactions2,
useTransactions,
} from 'loot-core/client/data-hooks/transactions';
import * as queries from 'loot-core/client/queries';
import { listen, send } from 'loot-core/platform/client/fetch';
import { isPreviewId } from 'loot-core/shared/transactions';
Expand Down Expand Up @@ -50,6 +56,11 @@ export function AccountTransactions({
readonly accountId?: string;
readonly accountName: string;
}) {
const schedulesQueryBuilder = useMemo(
() => defaultSchedulesQueryBuilder(accountId),
[accountId],
);

return (
<Page
header={
Expand All @@ -67,11 +78,13 @@ export function AccountTransactions({
}
padding={0}
>
<TransactionListWithPreviews
account={account}
accountName={accountName}
accountId={accountId}
/>
<SchedulesProvider queryBuilder={schedulesQueryBuilder}>
<TransactionListWithPreviews
account={account}
accountName={accountName}
accountId={accountId}
/>
</SchedulesProvider>
</Page>
);
}
Expand Down Expand Up @@ -222,12 +235,11 @@ function TransactionListWithPreviews({
updateQuery: updateTransactionsQuery,
} = useTransactions({
queryBuilder: () => baseTransactionsQuery().select('*'),
options: {
includePreviewTransactions: !isSearching,
schedulesQueryBuilder: useDefaultSchedulesQueryBuilder(accountId),
},
});

const { data: previewTransactions, isLoading: isPreviewTransactionsLoading } =
usePreviewTransactions2({ options: { isDisabled: isSearching } });

const dateFormat = useDateFormat() || 'MM/dd/yyyy';
const dispatch = useDispatch();
const navigate = useNavigate();
Expand Down Expand Up @@ -315,8 +327,8 @@ function TransactionListWithPreviews({

return (
<TransactionListWithBalances
isLoading={isLoading}
transactions={transactions}
isLoading={isLoading || isPreviewTransactionsLoading}
transactions={previewTransactions.concat(transactions)}
balance={balanceQueries.balance}
balanceCleared={balanceQueries.cleared}
balanceUncleared={balanceQueries.uncleared}
Expand Down
115 changes: 62 additions & 53 deletions packages/loot-core/src/client/data-hooks/schedules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import React, {
createContext,
useContext,
useEffect,
useMemo,
useState,
useRef,
useMemo,
type PropsWithChildren,
} from 'react';

Expand All @@ -18,7 +19,9 @@ import {
type AccountEntity,
} from '../../types/models';
import { accountFilter } from '../queries';
import { liveQuery } from '../query-helpers';
import { type LiveQuery, liveQuery } from '../query-helpers';

const defaultQuery = q('schedules').select('*');

export type ScheduleStatusType = ReturnType<typeof getStatus>;
export type ScheduleStatuses = Map<ScheduleEntity['id'], ScheduleStatusType>;
Expand Down Expand Up @@ -52,74 +55,82 @@ function loadStatuses(

type UseSchedulesProps = {
queryBuilder?: (q: Query) => Query;
options?: {
isDisabled?: boolean;
};
};
type ScheduleData = {
schedules: readonly ScheduleEntity[];
statuses: ScheduleStatuses;
};
type UseSchedulesResult = ScheduleData & {
readonly isLoading: boolean;
readonly isDisabled: boolean;
};

export function useSchedules({
queryBuilder,
options: { isDisabled } = { isDisabled: false },
}: UseSchedulesProps = {}): UseSchedulesResult {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState<ScheduleData>();
const [data, setData] = useState<ScheduleData>({
schedules: [],
statuses: new Map(),
});
const [upcomingLength] = useSyncedPref('upcomingScheduledTransactionLength');

const scheduleQueryRef = useRef<LiveQuery<ScheduleEntity> | null>(null);
const statusQueryRef = useRef<LiveQuery<TransactionEntity> | null>(null);
const query = useMemo(
() => queryBuilder?.(defaultQuery) ?? defaultQuery,
[queryBuilder],
);

useEffect(() => {
let isUnmounted = false;
if (isDisabled) {
setData({ schedules: [], statuses: new Map() });
return;
}

const query = q('schedules').select('*');
let statusQuery;
let isUnmounted = false;

setIsLoading(true);

const scheduleQuery = liveQuery<ScheduleEntity>(
queryBuilder ? queryBuilder(query) : query,
scheduleQueryRef.current = liveQuery<ScheduleEntity>(
query,
async schedules => {
if (scheduleQuery) {
if (statusQuery) {
statusQuery.unsubscribe();
}

statusQuery = loadStatuses(
schedules,
(statuses: ScheduleStatuses) => {
if (!isUnmounted) {
setIsLoading(false);
setData({ schedules, statuses });
}
},
upcomingLength,
);
}
statusQueryRef.current = loadStatuses(
schedules,
(statuses: ScheduleStatuses) => {
if (!isUnmounted) {
setIsLoading(false);
setData({ schedules, statuses });
}
},
upcomingLength,
);
},
);

return () => {
isUnmounted = true;

if (scheduleQuery) {
scheduleQuery.unsubscribe();
}
if (statusQuery) {
statusQuery.unsubscribe();
}
scheduleQueryRef.current?.unsubscribe();
statusQueryRef.current?.unsubscribe();
};
}, [upcomingLength, queryBuilder]);
}, [isDisabled, query, upcomingLength]);

return {
isLoading,
isDisabled,
...data,
};
}

type SchedulesContextValue = UseSchedulesResult;

const SchedulesContext = createContext<SchedulesContextValue>({
isLoading: true,
isLoading: false,
isDisabled: false,
schedules: [],
statuses: new Map(),
});
Expand All @@ -144,27 +155,25 @@ export function useCachedSchedules() {
return useContext(SchedulesContext);
}

export function useDefaultSchedulesQueryBuilder(
export function defaultSchedulesQueryBuilder(
accountId?: AccountEntity['id'] | 'budgeted' | 'offbudget' | 'uncategorized',
) {
return useMemo(() => {
const filterByAccount = accountFilter(accountId, '_account');
const filterByPayee = accountFilter(accountId, '_payee.transfer_acct');

return (q: Query) => {
q = q.filter({
$and: [{ '_account.closed': false }],
});
if (accountId) {
if (accountId === 'uncategorized') {
q = q.filter({ next_date: null });
} else {
q = q.filter({
$or: [filterByAccount, filterByPayee],
});
}
const filterByAccount = accountFilter(accountId, '_account');
const filterByPayee = accountFilter(accountId, '_payee.transfer_acct');

return (q: Query) => {
q = q.filter({
$and: [{ '_account.closed': false }],
});
if (accountId) {
if (accountId === 'uncategorized') {
q = q.filter({ next_date: null });
} else {
q = q.filter({
$or: [filterByAccount, filterByPayee],
});
}
return q.orderBy({ next_date: 'desc' });
};
}, [accountId]);
}
return q.orderBy({ next_date: 'desc' });
};
}
Loading

0 comments on commit 13d8a9e

Please sign in to comment.