From 3c9bd88842928319f8e8c72d0b17c82b7c84010e Mon Sep 17 00:00:00 2001 From: Maikel Maas Date: Wed, 21 Feb 2024 11:32:17 -0300 Subject: [PATCH] chore: created deleteExpiredStates() method, updated the docs and fixed broken tests --- .../xstatePersistence.entities.test.ts | 4 +-- .../__tests__/xstatePersistence.store.test.ts | 20 ++++------- .../entities/xstatePersistence/StateEntity.ts | 4 --- .../xstatePersistence/IAbstractXStateStore.ts | 2 -- .../src/xstatePersistence/XStateStore.ts | 3 +- .../xstate-persistence/plugin.schema.json | 36 +++++++++---------- .../src/agent/XStatePersistence.ts | 26 ++++++++++++-- .../src/types/IXStatePersistence.ts | 16 ++++++--- .../xstate-persistence/src/types/types.ts | 12 +++++-- 9 files changed, 68 insertions(+), 55 deletions(-) diff --git a/packages/data-store/src/__tests__/xstatePersistence.entities.test.ts b/packages/data-store/src/__tests__/xstatePersistence.entities.test.ts index 78c94fe29..2f4ff8aa5 100644 --- a/packages/data-store/src/__tests__/xstatePersistence.entities.test.ts +++ b/packages/data-store/src/__tests__/xstatePersistence.entities.test.ts @@ -29,8 +29,7 @@ describe('Database entities tests', (): void => { state: 'test_state', type: 'b40b8474-58a2-4b23-9fde-bd6ee1902cdb', completedAt: new Date(), - tenantId: 'test_tenant_id', - ttl: 30000 + tenantId: 'test_tenant_id' } const xstateEventEntity: StateEntity = stateEntityFrom(xstateEvent) @@ -41,7 +40,6 @@ describe('Database entities tests', (): void => { expect(fromDb?.type).toEqual(xstateEvent.type) expect(fromDb?.state).toEqual(xstateEvent.state) expect(fromDb?.tenantId).toEqual(xstateEvent.tenantId) - expect(fromDb?.ttl).toEqual(xstateEvent.ttl) expect(fromDb?.completedAt).toEqual(xstateEvent.completedAt) }) }) diff --git a/packages/data-store/src/__tests__/xstatePersistence.store.test.ts b/packages/data-store/src/__tests__/xstatePersistence.store.test.ts index f51ee2230..c732e0167 100644 --- a/packages/data-store/src/__tests__/xstatePersistence.store.test.ts +++ b/packages/data-store/src/__tests__/xstatePersistence.store.test.ts @@ -32,8 +32,7 @@ describe('Database entities tests', (): void => { createdAt: new Date(), updatedAt: new Date(), completedAt: new Date(), - tenantId: 'test_tenant_id', - ttl: 30000 + tenantId: 'test_tenant_id' } const savedXStoreEvent: State = await xstateStore.saveState(xstateEvent) @@ -45,8 +44,7 @@ describe('Database entities tests', (): void => { state: 'test_state', type: 'b40b8474-58a2-4b23-9fde-bd6ee1902cdb', completedAt: new Date(), - tenantId: 'test_tenant_id', - ttl: 30000 + tenantId: 'test_tenant_id' } const stateEvent1: NonPersistedXStateStoreEvent = await xstateStore.saveState({...xstateEvent}) @@ -64,8 +62,7 @@ describe('Database entities tests', (): void => { state: 'test_state', type: 'b40b8474-58a2-4b23-9fde-bd6ee1902cdb', completedAt: new Date(), - tenantId: 'test_tenant_id', - ttl: 30000 + tenantId: 'test_tenant_id' } const savedXStoreEvent1: State = await xstateStore.saveState(xstateEvent) @@ -90,16 +87,14 @@ describe('Database entities tests', (): void => { type: 'test_type_1', createdAt: now, completedAt: new Date(), - tenantId: 'test_tenant_id', - ttl: 30000 + tenantId: 'test_tenant_id' } const middleXstateEvent: NonPersistedXStateStoreEvent = { state: 'test_state', type: 'test_type_2', createdAt: new Date(+now - 30000), completedAt: new Date(), - tenantId: 'test_tenant_id', - ttl: 30000 + tenantId: 'test_tenant_id' } const oldestXstateEvent: NonPersistedXStateStoreEvent = { @@ -107,8 +102,7 @@ describe('Database entities tests', (): void => { type: 'test_type_3', createdAt: new Date(+now - 60000), completedAt: new Date(), - tenantId: 'test_tenant_id', - ttl: 30000 + tenantId: 'test_tenant_id' } await xstateStore.saveState(oldestXstateEvent) @@ -116,7 +110,7 @@ describe('Database entities tests', (): void => { await xstateStore.saveState(newestXstateEvent) await xstateStore.deleteState({ - where: `created_at < datetime('now', '-30 seconds')` + where: `created_at < datetime('now', :ttl)`, parameters: { ttl: '-30 seconds' } }) await expect(xstateStore.getState({ type: 'test_type_1'})).resolves.toBeDefined() diff --git a/packages/data-store/src/entities/xstatePersistence/StateEntity.ts b/packages/data-store/src/entities/xstatePersistence/StateEntity.ts index 72205a724..62e887b54 100644 --- a/packages/data-store/src/entities/xstatePersistence/StateEntity.ts +++ b/packages/data-store/src/entities/xstatePersistence/StateEntity.ts @@ -23,9 +23,6 @@ export class StateEntity extends BaseEntity { @Column({ name: 'tenant_id', type: 'varchar', nullable: true }) tenantId?: string - - @Column({ name: 'ttl', default: 0 }) - ttl!: number } export const stateEntityFrom = (args: NonPersistedXStateStoreEvent): StateEntity => { @@ -34,6 +31,5 @@ export const stateEntityFrom = (args: NonPersistedXStateStoreEvent): StateEntity stateEntity.type = args.type stateEntity.completedAt = args.completedAt stateEntity.tenantId = args.tenantId - stateEntity.ttl = args.ttl return stateEntity } diff --git a/packages/data-store/src/types/xstatePersistence/IAbstractXStateStore.ts b/packages/data-store/src/types/xstatePersistence/IAbstractXStateStore.ts index 2f3905282..aa567e2b1 100644 --- a/packages/data-store/src/types/xstatePersistence/IAbstractXStateStore.ts +++ b/packages/data-store/src/types/xstatePersistence/IAbstractXStateStore.ts @@ -7,7 +7,6 @@ export type SaveStateArgs = { updatedAt?: Date completedAt?: Date tenantId?: string - ttl: number } export type GetStateArgs = Pick @@ -31,5 +30,4 @@ export type State = { updatedAt: Date completedAt?: Date tenantId?: string - ttl: number } diff --git a/packages/data-store/src/xstatePersistence/XStateStore.ts b/packages/data-store/src/xstatePersistence/XStateStore.ts index 713e59838..dbfe705d1 100644 --- a/packages/data-store/src/xstatePersistence/XStateStore.ts +++ b/packages/data-store/src/xstatePersistence/XStateStore.ts @@ -62,8 +62,7 @@ export class XStateStore extends IAbstractXStateStore { createdAt: state.createdAt, updatedAt: state.updatedAt, completedAt: state.completedAt, - tenantId: state.tenantId, - ttl: state.ttl + tenantId: state.tenantId } } } diff --git a/packages/xstate-persistence/plugin.schema.json b/packages/xstate-persistence/plugin.schema.json index f6cd1b025..722ce770b 100644 --- a/packages/xstate-persistence/plugin.schema.json +++ b/packages/xstate-persistence/plugin.schema.json @@ -2,23 +2,27 @@ "IXStatePersistence": { "components": { "schemas": { - "DeleteStateArgs": { + "DeleteExpiredStatesArgs": { "type": "object", "properties": { - "where": { - "type": "string" + "duration": { + "type": "number" }, - "parameters": { - "$ref": "#/components/schemas/ObjectLiteral" + "dialect": { + "$ref": "#/components/schemas/SQLDialect" } }, "required": [ - "where" + "duration", + "dialect" ] }, - "ObjectLiteral": { - "type": "object", - "description": "Interface of the simple literal object with any string keys." + "SQLDialect": { + "type": "string", + "enum": [ + "SQLite3", + "PostgreSQL" + ] }, "DeleteStateResult": { "$ref": "#/components/schemas/VoidResult" @@ -67,17 +71,13 @@ }, "tenantId": { "type": "string" - }, - "ttl": { - "type": "number" } }, "required": [ "state", "type", "createdAt", - "updatedAt", - "ttl" + "updatedAt" ] }, "XStatePersistenceEvent": { @@ -125,15 +125,11 @@ }, "tenantId": { "type": "string" - }, - "ttl": { - "type": "number" } }, "required": [ "state", - "type", - "ttl" + "type" ] }, "OnEventResult": { @@ -144,7 +140,7 @@ "deleteExpiredStates": { "description": "Deletes the state of an xstate machine in the database.", "arguments": { - "$ref": "#/components/schemas/DeleteStateArgs" + "$ref": "#/components/schemas/DeleteExpiredStatesArgs" }, "returnType": { "$ref": "#/components/schemas/DeleteStateResult" diff --git a/packages/xstate-persistence/src/agent/XStatePersistence.ts b/packages/xstate-persistence/src/agent/XStatePersistence.ts index 01d98c7e1..78020b881 100644 --- a/packages/xstate-persistence/src/agent/XStatePersistence.ts +++ b/packages/xstate-persistence/src/agent/XStatePersistence.ts @@ -1,7 +1,8 @@ -import {DeleteStateArgs, IAbstractXStateStore} from "@sphereon/ssi-sdk.data-store"; +import {IAbstractXStateStore} from "@sphereon/ssi-sdk.data-store"; import {IAgentPlugin,} from '@veramo/core' import { + DeleteExpiredStatesArgs, DeleteStateResult, OnEventResult, RequiredContext, @@ -56,10 +57,29 @@ export class XStatePersistence implements IAgentPlugin { return this.store.getState(args) } - private async deleteExpiredStates(args: DeleteStateArgs): Promise { + private async deleteExpiredStates(args: DeleteExpiredStatesArgs): Promise { if (!this.store) { return Promise.reject(Error('No store available in options')) } - return this.store.deleteState(args) + switch (args.dialect) { + case 'SQLite3': + const sqLiteParams = { + where: `created_at < datetime('now', :duration)`, + params: { + duration: `-${args.duration / 1000} seconds` + } + } + return this.store.deleteState(sqLiteParams) + case 'PostgreSQL': + const postgreSQLParams = { + where: 'created_at < :duration', + params: { + duration: `NOW() - '${args.duration / 1000} seconds'::interval` + } + } + return this.store.deleteState(postgreSQLParams) + default: + return Promise.reject(Error('Invalid database dialect')) + } } } diff --git a/packages/xstate-persistence/src/types/IXStatePersistence.ts b/packages/xstate-persistence/src/types/IXStatePersistence.ts index 3d2cbcdb8..b859ae098 100644 --- a/packages/xstate-persistence/src/types/IXStatePersistence.ts +++ b/packages/xstate-persistence/src/types/IXStatePersistence.ts @@ -1,7 +1,7 @@ -import {DeleteStateArgs} from "@sphereon/ssi-sdk.data-store"; import {IPluginMethodMap} from '@veramo/core' import { + DeleteExpiredStatesArgs, DeleteStateResult, LoadStateArgs, LoadStateResult, @@ -22,7 +22,8 @@ export interface IXStatePersistence extends IPluginMethodMap { /** * Loads the state of an xstate machine from the database. * - * @param args + * @param args LoadStateArgs + * type of the event * * @returns state or null * @@ -34,15 +35,20 @@ export interface IXStatePersistence extends IPluginMethodMap { /** * Deletes the state of an xstate machine in the database. * - * @param args + * @param args DeleteExpiredStatesArgs + * duration in milliseconds + * dialect 'SQLite3' or 'PostgreSQL' * * @beta This API is likely to change without a BREAKING CHANGE notice */ - deleteExpiredStates(args: DeleteStateArgs): Promise + deleteExpiredStates(args: DeleteExpiredStatesArgs): Promise /** * Persists the state whenever an event is emitted - * @param event + * @param event XStatePersistenceEvent + * type of the event ('every' is the only one available at the moment) + * data of the event + * * @param context * @beta This API is likely to change without a BREAKING CHANGE notice */ diff --git a/packages/xstate-persistence/src/types/types.ts b/packages/xstate-persistence/src/types/types.ts index 278930fed..53d584152 100644 --- a/packages/xstate-persistence/src/types/types.ts +++ b/packages/xstate-persistence/src/types/types.ts @@ -9,14 +9,20 @@ export enum XStatePersistenceEventType { EVERY = 'every' } -export type PersistStateArgs = SaveStateArgs +export enum SQLDialect { + SQLite3 = 'SQLite3', + PostgreSQL = 'PostgreSQL', +} + +export type DeleteExpiredStatesArgs = { + duration: number, + dialect: SQLDialect, +} export type NonPersistedXStatePersistenceEvent = SaveStateArgs export type LoadStateArgs = GetStateArgs -export type PersistStateResult = VoidResult - export type LoadStateResult = State export type DeleteStateResult = VoidResult