From c0c8eb6afba339e07b53adb500850cbf1e1cc226 Mon Sep 17 00:00:00 2001 From: jaxoncreed Date: Mon, 2 Oct 2023 23:43:09 -0400 Subject: [PATCH] Fixed batching problem --- packages/demo-react/src/App.tsx | 4 +- packages/demo-react/src/Header.tsx | 36 ++++++++----- packages/demo-react/src/Layout.tsx | 51 ++++++++++++------- packages/demo-react/src/profile/Profile.tsx | 34 +++++++++++++ packages/solid/src/requester/LeafRequester.ts | 8 ++- .../requester/requests/updateDataResource.ts | 20 ++------ packages/solid/src/util/RequestBatcher.ts | 9 ++-- 7 files changed, 108 insertions(+), 54 deletions(-) create mode 100644 packages/demo-react/src/profile/Profile.tsx diff --git a/packages/demo-react/src/App.tsx b/packages/demo-react/src/App.tsx index 8cc2ffd..721b93e 100644 --- a/packages/demo-react/src/App.tsx +++ b/packages/demo-react/src/App.tsx @@ -1,12 +1,12 @@ import type { FunctionComponent } from "react"; import React from "react"; -import { Layout } from "./Layout"; +import { Router } from "./Layout"; import { BrowserSolidLdoProvider } from "@ldo/solid-react"; const ProfileApp: FunctionComponent = () => { return ( - + ); }; diff --git a/packages/demo-react/src/Header.tsx b/packages/demo-react/src/Header.tsx index 289f044..49f751d 100644 --- a/packages/demo-react/src/Header.tsx +++ b/packages/demo-react/src/Header.tsx @@ -3,6 +3,7 @@ import type { FunctionComponent } from "react"; import React from "react"; import { useResource, useSolidAuth, useSubject } from "@ldo/solid-react"; import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; +import { Link } from "react-router-dom"; const DEFAULT_ISSUER = "https://solidweb.me"; @@ -27,20 +28,27 @@ export const Header: FunctionComponent = () => { const [issuer, setIssuer] = useState(DEFAULT_ISSUER); const { login, signUp, session } = useSolidAuth(); return ( -
- {session.isLoggedIn ? ( - - ) : ( - <> - setIssuer(e.target.value)} - /> - - - - )} +
+
+ {session.isLoggedIn ? ( + + ) : ( + <> + setIssuer(e.target.value)} + /> + + + + )} +
+

+ Blog + {" "} + Profile +

); }; diff --git a/packages/demo-react/src/Layout.tsx b/packages/demo-react/src/Layout.tsx index bdc30a2..0521d3f 100644 --- a/packages/demo-react/src/Layout.tsx +++ b/packages/demo-react/src/Layout.tsx @@ -1,35 +1,50 @@ import { useSolidAuth } from "@ldo/solid-react"; -import React from "react"; +import React, { Fragment } from "react"; import type { FunctionComponent } from "react"; -import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import { createBrowserRouter, Outlet, RouterProvider } from "react-router-dom"; import { Blog } from "./blog/Blog"; import { PostPage } from "./post/PostPage"; import { Header } from "./Header"; import { MainContainerProvider } from "./MainContainerProvider"; - -const router = createBrowserRouter([ - { - path: "/", - element: , - }, - { - path: "/media/:uri", - element: , - }, -]); +import { Profile } from "./profile/Profile"; export const Layout: FunctionComponent = () => { - const { session, ranInitialAuthCheck } = useSolidAuth(); - if (!ranInitialAuthCheck) { - return

Loading

; - } + const { session } = useSolidAuth(); return (

- {session.isLoggedIn ? : undefined} + {session.isLoggedIn ? : }
); }; + +const router = createBrowserRouter([ + { + element: , + children: [ + { + path: "/", + element: , + }, + { + path: "/media/:uri", + element: , + }, + { + path: "/profile", + element: , + }, + ], + }, +]); + +export const Router: FunctionComponent = () => { + const { ranInitialAuthCheck } = useSolidAuth(); + if (!ranInitialAuthCheck) { + return

Loading

; + } + return ; +}; diff --git a/packages/demo-react/src/profile/Profile.tsx b/packages/demo-react/src/profile/Profile.tsx new file mode 100644 index 0000000..ae57f90 --- /dev/null +++ b/packages/demo-react/src/profile/Profile.tsx @@ -0,0 +1,34 @@ +import { + useLdo, + useResource, + useSolidAuth, + useSubject, +} from "@ldo/solid-react"; +import type { ChangeEvent } from "react"; +import React, { useCallback, type FunctionComponent } from "react"; +import { SolidProfileShapeShapeType } from "../.ldo/solidProfile.shapeTypes"; + +export const Profile: FunctionComponent = () => { + const { session } = useSolidAuth(); + const profile = useSubject(SolidProfileShapeShapeType, session.webId); + const webIdResource = useResource(session.webId); + const { changeData, commitData } = useLdo(); + + const onNameChange = useCallback( + async (e: ChangeEvent) => { + if (profile && webIdResource) { + const cProfile = changeData(profile, webIdResource); + cProfile.fn = e.target.value; + await commitData(cProfile); + } + }, + [profile, webIdResource], + ); + + return ( + <> + + + + ); +}; diff --git a/packages/solid/src/requester/LeafRequester.ts b/packages/solid/src/requester/LeafRequester.ts index 9ca93eb..86b605a 100644 --- a/packages/solid/src/requester/LeafRequester.ts +++ b/packages/solid/src/requester/LeafRequester.ts @@ -56,12 +56,18 @@ export class LeafRequester extends Requester { async updateDataResource( changes: DatasetChanges, ): Promise { + const transaction = this.context.solidLdoDataset.startTransaction(); + transaction.addAll(changes.added || []); + changes.removed?.forEach((quad) => transaction.delete(quad)); + // Commit data optimistically + transaction.commit(); + const result = await this.requestBatcher.queueProcess({ name: UPDATE_KEY, args: [ this.uri, changes, - { fetch: this.context.fetch, dataset: this.context.solidLdoDataset }, + { fetch: this.context.fetch, onRollback: () => transaction.rollback() }, ], perform: updateDataResource, modifyQueue: (queue, isLoading, [, changes]) => { diff --git a/packages/solid/src/requester/requests/updateDataResource.ts b/packages/solid/src/requester/requests/updateDataResource.ts index d76ddbb..3705796 100644 --- a/packages/solid/src/requester/requests/updateDataResource.ts +++ b/packages/solid/src/requester/requests/updateDataResource.ts @@ -1,9 +1,5 @@ import type { DatasetChanges } from "@ldo/rdf-utils"; import { changesToSparqlUpdate } from "@ldo/rdf-utils"; -import type { - SubscribableDataset, - TransactionalDataset, -} from "@ldo/subscribable-dataset"; import type { Quad } from "@rdfjs/types"; import { guaranteeFetch } from "../../util/guaranteeFetch"; import type { LeafUri } from "../../util/uriTypes"; @@ -19,19 +15,11 @@ export type UpdateResultError = HttpErrorResultType | UnexpectedResourceError; export async function updateDataResource( uri: LeafUri, datasetChanges: DatasetChanges, - options?: BasicRequestOptions & { dataset?: SubscribableDataset }, + options?: BasicRequestOptions & { onRollback?: () => void }, ): Promise { try { const fetch = guaranteeFetch(options?.fetch); - // Put Changes in transactional dataset - let transaction: TransactionalDataset | undefined; - if (options?.dataset) { - transaction = options.dataset.startTransaction(); - transaction.addAll(datasetChanges.added || []); - datasetChanges.removed?.forEach((quad) => transaction!.delete(quad)); - // Commit data optimistically - transaction.commit(); - } + // Make request const sparqlUpdate = await changesToSparqlUpdate(datasetChanges); const response = await fetch(uri, { @@ -44,8 +32,8 @@ export async function updateDataResource( const httpError = HttpErrorResult.checkResponse(uri, response); if (httpError) { // Handle error rollback - if (transaction) { - transaction.rollback(); + if (options?.onRollback) { + options.onRollback(); } return httpError; } diff --git a/packages/solid/src/util/RequestBatcher.ts b/packages/solid/src/util/RequestBatcher.ts index 3f0a287..0f95309 100644 --- a/packages/solid/src/util/RequestBatcher.ts +++ b/packages/solid/src/util/RequestBatcher.ts @@ -66,11 +66,14 @@ export class RequestBatcher { const timeSinceLastTrigger = Date.now() - lastRequestTimestamp; const triggerProcess = async () => { - this.isWaiting = false; + if (this.isWaiting) { + return; + } this.lastRequestTimestampMap[processName] = Date.now(); this.lastRequestTimestampMap[ANY_KEY] = Date.now(); const processToTrigger = this.processQueue.shift(); if (processToTrigger) { + this.isWaiting = true; try { const returnValue = await processToTrigger.perform( ...processToTrigger.args, @@ -83,6 +86,7 @@ export class RequestBatcher { callback(err); }); } + this.isWaiting = false; // Reset loading if ( @@ -101,8 +105,7 @@ export class RequestBatcher { } }; - if (timeSinceLastTrigger < this.batchMillis && !this.isWaiting) { - this.isWaiting = true; + if (timeSinceLastTrigger < this.batchMillis) { setTimeout(triggerProcess, this.batchMillis - timeSinceLastTrigger); } else { triggerProcess();