From aec63713ba4f95fc03cf044852a45b8083ae01d0 Mon Sep 17 00:00:00 2001 From: acaldas Date: Fri, 20 Sep 2024 11:43:45 +0100 Subject: [PATCH] feat: improved handling of graphql responses and type improvements --- .../listener/transmitter/pull-responder.ts | 40 ++++++++++++++---- src/storage/memory.ts | 6 +-- src/utils/graphql.ts | 41 ++++++++++--------- test/utils.ts | 6 +-- 4 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/server/listener/transmitter/pull-responder.ts b/src/server/listener/transmitter/pull-responder.ts index f52f2c7..22ddc41 100644 --- a/src/server/listener/transmitter/pull-responder.ts +++ b/src/server/listener/transmitter/pull-responder.ts @@ -117,7 +117,7 @@ export class PullResponderTransmitter implements IPullResponderTransmitter { filter: ListenerFilter ): Promise { // graphql request to switchboard - const { registerPullResponderListener } = await requestGraphql<{ + const result = await requestGraphql<{ registerPullResponderListener: { listenerId: Listener['listenerId']; }; @@ -134,7 +134,17 @@ export class PullResponderTransmitter implements IPullResponderTransmitter { `, { filter } ); - return registerPullResponderListener.listenerId; + + const error = result.errors?.at(0); + if (error) { + throw error; + } + + if (!result.registerPullResponderListener) { + throw new Error('Error registering listener'); + } + + return result.registerPullResponderListener.listenerId; } static async pullStrands( @@ -143,11 +153,7 @@ export class PullResponderTransmitter implements IPullResponderTransmitter { listenerId: string, options?: GetStrandsOptions // TODO add support for since ): Promise { - const { - system: { - sync: { strands } - } - } = await requestGraphql( + const result = await requestGraphql( url, gql` query strands($listenerId: ID!) { @@ -188,7 +194,17 @@ export class PullResponderTransmitter implements IPullResponderTransmitter { `, { listenerId } ); - return strands.map(s => ({ + + const error = result.errors?.at(0); + if (error) { + throw error; + } + + if (!result.system) { + return []; + } + + return result.system.sync.strands.map(s => ({ ...s, operations: s.operations.map(o => ({ ...o, @@ -215,6 +231,14 @@ export class PullResponderTransmitter implements IPullResponderTransmitter { `, { listenerId, revisions } ); + const error = result.errors?.at(0); + if (error) { + throw error; + } + + if (result.acknowledge === null) { + throw new Error('Error acknowledging strands'); + } return result.acknowledge; } diff --git a/src/storage/memory.ts b/src/storage/memory.ts index 6f6cb79..3f88499 100644 --- a/src/storage/memory.ts +++ b/src/storage/memory.ts @@ -44,7 +44,7 @@ export class MemoryStorage implements IDriveStorage { async saveDocument(drive: string, id: string, document: Document) { this.documents[drive] = this.documents[drive] ?? {}; - this.documents[drive]![id] = document; + this.documents[drive][id] = document; } async clearStorage(): Promise { @@ -65,7 +65,7 @@ export class MemoryStorage implements IDriveStorage { clipboard, state } = document; - this.documents[drive]![id] = { + this.documents[drive][id] = { operations, initialState, name, @@ -105,7 +105,7 @@ export class MemoryStorage implements IDriveStorage { if (!this.documents[drive]) { throw new DriveNotFoundError(drive); } - delete this.documents[drive]![id]; + delete this.documents[drive][id]; } async getDrives() { diff --git a/src/utils/graphql.ts b/src/utils/graphql.ts index ca551bc..432edb9 100644 --- a/src/utils/graphql.ts +++ b/src/utils/graphql.ts @@ -171,6 +171,27 @@ export type DriveState = DriveInfo & nodes: Array>; }; +export type DocumentGraphQLResult = Pick< + D, + 'name' | 'created' | 'documentType' | 'lastModified' +> & { + id: string; + revision: number; + state: InferDocumentState; + initialState: InferDocumentState; + operations: (Pick< + Operation, + | 'id' + | 'hash' + | 'index' + | 'skip' + | 'timestamp' + | 'type' + | 'error' + | 'context' + > & { inputText: string })[]; +}; + export async function fetchDocument( url: string, documentId: string, @@ -192,25 +213,7 @@ export async function fetchDocument( const stateFields = generateDocumentStateQueryFields(documentModel); const name = pascalCase(documentModel.name); const result = await requestGraphql<{ - document: Pick< - D, - 'name' | 'created' | 'documentType' | 'lastModified' - > & { - id: string; - revision: number; - state: InferDocumentState; - initialState: InferDocumentState; - operations: (Pick< - Operation, - | 'id' - | 'hash' - | 'index' - | 'skip' - | 'timestamp' - | 'type' - | 'error' - > & { inputText: string })[]; - }; + document: DocumentGraphQLResult; }>( url, gql` diff --git a/test/utils.ts b/test/utils.ts index 4fd0932..167e055 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -9,7 +9,7 @@ import { } from 'document-model/document'; import { DocumentModelDocument } from 'document-model/document-model'; import { ExpectStatic } from 'vitest'; -import { DocumentDriveServer } from '../src'; +import { BaseDocumentDriveServer } from '../src'; export function expectUUID(expect: ExpectStatic): unknown { return expect.stringMatching( @@ -93,7 +93,7 @@ export class BasicClient { private unsyncedOperations: Operation[] = []; constructor( - private server: DocumentDriveServer, + private server: BaseDocumentDriveServer, private driveId: string, private documentId: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -166,7 +166,7 @@ export class DriveBasicClient { []; constructor( - private server: DocumentDriveServer, + private server: BaseDocumentDriveServer, private driveId: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any private document: Document,