Include pagination for app queries

This commit is contained in:
Hakan Shehu
2024-08-30 13:51:55 +02:00
parent 55142f9786
commit 10cbefd150
6 changed files with 83 additions and 42 deletions

View File

@@ -33,20 +33,23 @@ export const App = () => {
const accountsQuery = useQuery({
queryKey: ['accounts'],
queryFn: async () => {
queryFn: async ({ queryKey }) => {
const query = appDatabase.selectFrom('accounts').selectAll().compile();
return await window.neuron.executeAppQueryAndSubscribe('accounts', query);
return await window.neuron.executeAppQueryAndSubscribe({
key: queryKey,
query: query,
});
},
});
const workspacesQuery = useQuery({
queryKey: ['workspaces'],
queryFn: async () => {
queryFn: async ({ queryKey }) => {
const query = appDatabase.selectFrom('workspaces').selectAll().compile();
return await window.neuron.executeAppQueryAndSubscribe(
'workspaces',
query,
);
return await window.neuron.executeAppQueryAndSubscribe({
key: queryKey,
query: query,
});
},
});
@@ -61,8 +64,8 @@ export const App = () => {
value={{
database: appDatabase,
query: (query) => window.neuron.executeAppQuery(query),
queryAndSubscribe: (queryId, query) =>
window.neuron.executeAppQueryAndSubscribe(queryId, query),
queryAndSubscribe: (context) =>
window.neuron.executeAppQueryAndSubscribe(context),
mutate: (mutation) => window.neuron.executeAppMutation(mutation),
}}
>
@@ -84,8 +87,8 @@ export const App = () => {
value={{
database: appDatabase,
query: (query) => window.neuron.executeAppQuery(query),
queryAndSubscribe: (queryId, query) =>
window.neuron.executeAppQueryAndSubscribe(queryId, query),
queryAndSubscribe: (context) =>
window.neuron.executeAppQueryAndSubscribe(context),
mutate: (mutation) => window.neuron.executeAppMutation(mutation),
}}
>

View File

@@ -53,10 +53,43 @@ export const Root = () => {
const id = eventBus.subscribe((event) => {
if (event.event === 'app_query_updated') {
const result = event.payload.result;
const queryKey = event.payload.queryId;
const queryKey = event.payload.key;
const page = event.payload.page;
if (result && queryKey) {
queryClient.setQueryData([queryKey], result);
if (!result) {
return;
}
if (!queryKey) {
return;
}
const existingData = queryClient.getQueryData<any>(queryKey);
if (!existingData) {
window.neuron.unsubscribeAppQuery(queryKey);
return;
}
if (page !== undefined && page != null) {
const index = existingData.pageParams.indexOf(page);
if (index === -1) {
return;
}
const newData = {
pageParams: existingData.pageParams,
pages: existingData.pages.map((p: any, i: number) => {
if (i === index) {
return result;
}
return p;
}),
};
queryClient.setQueryData(queryKey, newData);
} else {
queryClient.setQueryData(queryKey, result);
}
}
});
@@ -68,8 +101,7 @@ export const Root = () => {
event.query.queryKey &&
event.query.queryKey.length > 0
) {
const queryKey = event.query.queryKey[0];
await window.neuron.unsubscribeAppQuery(queryKey);
await window.neuron.unsubscribeAppQuery(event.query.queryKey);
}
});

View File

@@ -1,14 +1,14 @@
import React from 'react';
import { CompiledQuery, Kysely, QueryResult } from 'kysely';
import { AppDatabaseSchema } from '@/data/schemas/app';
import { SubscribedQueryContext } from '@/types/databases';
interface AppDatabaseContext {
database: Kysely<AppDatabaseSchema>;
mutate: (mutation: CompiledQuery) => Promise<void>;
query: <R>(query: CompiledQuery<R>) => Promise<QueryResult<R>>;
queryAndSubscribe: <R>(
queryId: string,
query: CompiledQuery<R>,
context: SubscribedQueryContext<R>,
) => Promise<QueryResult<R>>;
}

View File

@@ -17,8 +17,12 @@ import {
resultHasChanged,
} from '@/data/utils';
import { Workspace } from '@/types/workspaces';
import { SubscribedQueryResult } from '@/types/databases';
import {
SubscribedQueryContext,
SubscribedQueryResult,
} from '@/types/databases';
import { eventBus } from '@/lib/event-bus';
import { isEqual } from 'lodash';
const EVENT_LOOP_INTERVAL = 1000;
@@ -75,23 +79,20 @@ class AppManager {
}
public async executeQueryAndSubscribe<T>(
queryId: string,
query: CompiledQuery<T>,
context: SubscribedQueryContext<T>,
): Promise<QueryResult<T>> {
await this.waitForInit();
const result = await this.database.executeQuery(query);
const result = await this.database.executeQuery(context.query);
// only mutations should have side effects
if (result.numAffectedRows > 0) {
throw new Error('Query should not have any side effects');
}
const selectedTables = extractTablesFromSql(query.sql);
const queryId = context.key.join('|') + context.page;
const selectedTables = extractTablesFromSql(context.query.sql);
const subscriberData: SubscribedQueryResult<T> = {
context: {
query,
key: [queryId],
},
context,
tables: selectedTables,
result: result,
};
@@ -145,8 +146,8 @@ class AppManager {
}
}
for (const [subscriberId, subscriberData] of this.subscribers) {
const hasAffectedTables = subscriberData.tables.some((table) =>
for (const subscriber of this.subscribers.values()) {
const hasAffectedTables = subscriber.tables.some((table) =>
affectedTables.includes(table),
);
@@ -155,14 +156,15 @@ class AppManager {
}
const newResult = await this.database.executeQuery(
subscriberData.context.query,
subscriber.context.query,
);
if (resultHasChanged(subscriberData.result, newResult)) {
if (resultHasChanged(subscriber.result, newResult)) {
eventBus.publish({
event: 'app_query_updated',
payload: {
queryId: subscriberId,
key: subscriber.context.key,
page: subscriber.context.page,
result: newResult,
},
});
@@ -170,8 +172,14 @@ class AppManager {
}
}
public unsubscribeQuery(queryId: string): void {
this.subscribers.delete(queryId);
public unsubscribeQuery(queryKey: string[]): void {
var queryIds = [...this.subscribers.keys()];
for (const queryId of queryIds) {
const subscriberData = this.subscribers.get(queryId);
if (isEqual(subscriberData.context.key, queryKey)) {
this.subscribers.delete(queryId);
}
}
}
public async logout(accountId: string): Promise<void> {

View File

@@ -88,15 +88,14 @@ ipcMain.handle(
'execute-app-query-and-subscribe',
async (
_,
queryId: string,
query: CompiledQuery<unknown>,
context: SubscribedQueryContext<unknown>,
): Promise<QueryResult<unknown>> => {
return await appManager.executeQueryAndSubscribe(queryId, query);
return await appManager.executeQueryAndSubscribe(context);
},
);
ipcMain.handle('unsubscribe-app-query', (_, queryId: string): void => {
appManager.unsubscribeQuery(queryId);
ipcMain.handle('unsubscribe-app-query', (_, queryKey: string[]): void => {
appManager.unsubscribeQuery(queryKey);
});
ipcMain.handle(

View File

@@ -9,10 +9,9 @@ interface NeuronApi {
executeAppMutation: (mutation: CompiledQuery) => Promise<void>;
executeAppQuery: (query: CompiledQuery<R>) => Promise<QueryResult<R>>;
executeAppQueryAndSubscribe: (
queryId: string,
query: CompiledQuery<R>,
context: SubscribedQueryContext<R>,
) => Promise<QueryResult<R>>;
unsubscribeAppQuery: (queryId: string) => Promise<void>;
unsubscribeAppQuery: (queryKey: string[]) => Promise<void>;
executeWorkspaceMutation: (
accountId: string,