diff --git a/packages/jsonld-dataset-proxy/src/arrayProxy/modifyArray.ts b/packages/jsonld-dataset-proxy/src/arrayProxy/modifyArray.ts index 54cd5df..b1ae921 100644 --- a/packages/jsonld-dataset-proxy/src/arrayProxy/modifyArray.ts +++ b/packages/jsonld-dataset-proxy/src/arrayProxy/modifyArray.ts @@ -1,7 +1,10 @@ import { defaultGraph } from "@rdfjs/data-model"; import type { Quad } from "@rdfjs/types"; import type { ObjectNode } from "@ldo/rdf-utils"; -import { ProxyTransactionalDataset } from "@ldo/subscribable-dataset"; +import { + TransactionDataset, + createTransactionDatasetFactory, +} from "@ldo/subscribable-dataset"; import { createDatasetFactory } from "@ldo/dataset"; import type { ProxyContext } from "../ProxyContext"; import { addObjectToDataset } from "../util/addObjectToDataset"; @@ -31,9 +34,10 @@ export function checkArrayModification( ); } // Create a test dataset to see if the inputted data is valid - const testDataset = new ProxyTransactionalDataset( + const testDataset = new TransactionDataset( proxyContext.dataset, createDatasetFactory(), + createTransactionDatasetFactory(), ); addObjectToDataset( objectToAdd as RawObject, diff --git a/packages/solid/src/SolidLdoTransactionDataset.ts b/packages/solid/src/SolidLdoTransactionDataset.ts index 8c57c0d..cbacbb3 100644 --- a/packages/solid/src/SolidLdoTransactionDataset.ts +++ b/packages/solid/src/SolidLdoTransactionDataset.ts @@ -10,7 +10,10 @@ import { } from "./util/uriTypes"; import type { SolidLdoDatasetContext } from "./SolidLdoDatasetContext"; import type { DatasetFactory, Quad } from "@rdfjs/types"; -import type { ITransactionDatasetFactory } from "@ldo/subscribable-dataset"; +import { + updateDatasetInBulk, + type ITransactionDatasetFactory, +} from "@ldo/subscribable-dataset"; import type { SolidLdoDataset } from "./SolidLdoDataset"; import type { AggregateSuccess } from "./requester/results/success/SuccessResult"; import type { ResourceResult } from "./resource/resourceResult/ResourceResult"; @@ -124,7 +127,7 @@ export class SolidLdoTransactionDataset async ([graph, datasetChanges]) => { if (graph.termType === "DefaultGraph") { // Undefined means that this is the default graph - this.parentDataset.bulk(datasetChanges); + updateDatasetInBulk(this.parentDataset, datasetChanges); return [ graph, datasetChanges, diff --git a/packages/subscribable-dataset/src/TransactionDataset.ts b/packages/subscribable-dataset/src/TransactionDataset.ts index 4b92fff..9e8ef3c 100644 --- a/packages/subscribable-dataset/src/TransactionDataset.ts +++ b/packages/subscribable-dataset/src/TransactionDataset.ts @@ -1,12 +1,9 @@ import type { Dataset, BaseQuad, Term, DatasetFactory } from "@rdfjs/types"; import type { DatasetChanges } from "@ldo/rdf-utils"; -import type { - ISubscribableDataset, - ITransactionDataset, - ITransactionDatasetFactory, -} from "./types"; +import type { ITransactionDataset, ITransactionDatasetFactory } from "./types"; import { mergeDatasetChanges } from "./mergeDatasetChanges"; import { SubscribableDataset } from "./SubscribableDataset"; +import { updateDatasetInBulk } from "./util"; /** * Proxy Transactional Dataset is a transactional dataset that does not duplicate @@ -20,7 +17,7 @@ export class TransactionDataset /** * The parent dataset that will be updated upon commit */ - public readonly parentDataset: ISubscribableDataset; + public readonly parentDataset: Dataset; /** * The changes made that are ready to commit @@ -41,7 +38,7 @@ export class TransactionDataset * @param parentDataset The dataset that will be updated upon commit */ constructor( - parentDataset: ISubscribableDataset, + parentDataset: Dataset, datasetFactory: DatasetFactory, transactionDatasetFactory: ITransactionDatasetFactory, ) { @@ -250,7 +247,7 @@ export class TransactionDataset * Helper method to update the parent dataset or any other provided dataset */ private updateParentDataset(datasetChanges: DatasetChanges) { - this.parentDataset.bulk(datasetChanges); + return updateDatasetInBulk(this.parentDataset, datasetChanges); } /** diff --git a/packages/subscribable-dataset/src/index.ts b/packages/subscribable-dataset/src/index.ts index 071e05d..a48f3f1 100644 --- a/packages/subscribable-dataset/src/index.ts +++ b/packages/subscribable-dataset/src/index.ts @@ -6,3 +6,4 @@ export * from "./SubscribableDataset"; export * from "./SubscribableDatasetFactory"; export * from "./types"; export * from "./mergeDatasetChanges"; +export * from "./util"; diff --git a/packages/subscribable-dataset/src/types.ts b/packages/subscribable-dataset/src/types.ts index 41f2de7..055ed21 100644 --- a/packages/subscribable-dataset/src/types.ts +++ b/packages/subscribable-dataset/src/types.ts @@ -151,7 +151,7 @@ export interface ITransactionDatasetFactory< InAndOutQuad extends BaseQuad = BaseQuad, > { transactionDataset( - parent: ISubscribableDataset, + parent: Dataset, ): ITransactionDataset; } @@ -160,7 +160,7 @@ export interface ITransactionDatasetFactory< */ export interface ITransactionDataset extends ISubscribableDataset { - readonly parentDataset: ISubscribableDataset; + readonly parentDataset: Dataset; rollback(): void; commit(): void; getChanges(): DatasetChanges; diff --git a/packages/subscribable-dataset/src/util.ts b/packages/subscribable-dataset/src/util.ts new file mode 100644 index 0000000..cfb8667 --- /dev/null +++ b/packages/subscribable-dataset/src/util.ts @@ -0,0 +1,27 @@ +import type { DatasetChanges } from "@ldo/rdf-utils"; +import type { BaseQuad, Dataset } from "@rdfjs/types"; +import type { IBulkEditableDataset } from "./types"; + +/** + * Performs a bulk update for a dataset even if it doesn't have a bulk method. + * @param dataset - the input dataset + * @param datasetChanges - changes to be applied + */ +export function updateDatasetInBulk( + dataset: Dataset, + datasetChanges: DatasetChanges, +) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((dataset as any).bulk) { + (dataset as IBulkEditableDataset).bulk(datasetChanges); + } else { + if (datasetChanges.added) { + dataset.addAll(datasetChanges.added); + } + if (datasetChanges.removed) { + datasetChanges.removed.forEach((curQuad) => { + dataset.delete(curQuad); + }); + } + } +} diff --git a/packages/subscribable-dataset/test/TransactionalDataset.test.ts b/packages/subscribable-dataset/test/TransactionalDataset.test.ts index 30c0dbf..903feef 100644 --- a/packages/subscribable-dataset/test/TransactionalDataset.test.ts +++ b/packages/subscribable-dataset/test/TransactionalDataset.test.ts @@ -6,7 +6,7 @@ import type { DatasetCore, } from "@rdfjs/types"; import type { ISubscribableDataset } from "../src"; -import { ExtendedDatasetFactory } from "@ldo/dataset"; +import { ExtendedDatasetFactory, createDataset } from "@ldo/dataset"; import { TransactionDataset, createSubscribableDataset, @@ -323,6 +323,24 @@ describe("TransactionDataset", () => { expect(mockParent.bulk).toHaveBeenCalled(); }); + it("Uses bulk update on commit when the parent dataset is not bulk updatable", () => { + // Disable for tests + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const mockParent: Dataset = createDataset([tomTypeQuad]); + transactionalDataset = new TransactionDataset( + mockParent, + extendedDatasetFactory, + createTransactionDatasetFactory(), + ); + + transactionalDataset.add(lickyNameQuad); + transactionalDataset.delete(tomTypeQuad); + transactionalDataset.commit(); + expect(mockParent.has(lickyNameQuad)).toBe(true); + expect(mockParent.has(tomTypeQuad)).toBe(false); + }); + it("Returns a transactional dataset", () => { expect( transactionalDataset.startTransaction() instanceof TransactionDataset,