@aerogear/apollo-voyager-conflicts
Advanced tools
Comparing version 0.1.0-alpha to 0.2.7-SNAPSHOT
import { ObjectStateData } from './ObjectStateData'; | ||
import { ConflictResolution } from './ConflictResolution'; | ||
/** | ||
@@ -8,2 +9,2 @@ * @param serverState server side data | ||
*/ | ||
export declare type ConflictResolutionHandler = (serverState: ObjectStateData, clientState: ObjectStateData) => void; | ||
export declare type ConflictResolutionHandler = (serverState: ObjectStateData, clientState: ObjectStateData, baseState?: ObjectStateData) => Promise<ConflictResolution> | ConflictResolution; |
@@ -0,1 +1,4 @@ | ||
import { ConflictLogger } from './ConflictLogger'; | ||
import { ConflictResolution } from './ConflictResolution'; | ||
import { ConflictResolutionStrategy } from './ConflictResolutionStrategy'; | ||
import { ObjectStateData } from './ObjectStateData'; | ||
@@ -11,11 +14,28 @@ /** | ||
* | ||
* @param serverData the data currently on the server | ||
* @param clientData the data the client wishes to perform some mutation with | ||
* @param serverState the data currently on the server | ||
* @param clientState the data the client wishes to perform some mutation with | ||
*/ | ||
hasConflict(serverData: ObjectStateData, clientData: ObjectStateData): boolean; | ||
hasConflict(serverState: ObjectStateData, clientState: ObjectStateData): boolean; | ||
/** | ||
* | ||
* @param currentObjectState the object wish you would like to progress to its next state | ||
* @param objectState the object wish you would like to progress to its next state | ||
*/ | ||
nextState(currentObjectState: ObjectStateData): ObjectStateData; | ||
nextState(objectState: ObjectStateData): ObjectStateData; | ||
/** | ||
* | ||
* @param serverState the current state of the object on the server | ||
* @param clientState the state of the object the client wishes to perform some mutation with | ||
*/ | ||
resolveOnClient(serverState: ObjectStateData, clientState: ObjectStateData): ConflictResolution; | ||
/** | ||
* | ||
* @param serverState the current state of the object on the server | ||
* @param clientState the state of the object the client wishes to perform some mutation with | ||
*/ | ||
resolveOnServer(strategy: ConflictResolutionStrategy, serverState: ObjectStateData, clientState: ObjectStateData): Promise<ConflictResolution>; | ||
/** | ||
* Enable logging for conflict resolution package | ||
* @param logger - logger implementation | ||
*/ | ||
enableLogging(logger: ConflictLogger): void; | ||
} |
@@ -7,1 +7,2 @@ import { ConflictResolutionHandler } from '../api/ConflictHandler'; | ||
export declare const handleConflictOnClient: ConflictResolutionHandler; | ||
export declare const resolveOnServer: ConflictResolutionHandler; |
@@ -7,3 +7,3 @@ "use strict"; | ||
const debug_1 = __importDefault(require("debug")); | ||
const ObjectConflictError_1 = require("../api/ObjectConflictError"); | ||
const ConflictResolution_1 = require("../api/ConflictResolution"); | ||
const constants_1 = require("../constants"); | ||
@@ -15,12 +15,12 @@ const logger = debug_1.default(constants_1.CONFLICT_LOGGER); | ||
*/ | ||
exports.handleConflictOnClient = (serverState, clientState) => { | ||
exports.handleConflictOnClient = function (serverState, clientState) { | ||
logger(`Conflict detected. | ||
Sending data to resolve conflict on client | ||
Server: ${serverState} client: ${clientState}`); | ||
throw new ObjectConflictError_1.ObjectConflictError({ | ||
clientData: clientState, | ||
serverData: serverState, | ||
resolvedOnServer: false | ||
}); | ||
return new ConflictResolution_1.ConflictResolution(false, serverState, clientState); | ||
}; | ||
exports.resolveOnServer = async function (strategy, serverState, clientState, baseState) { | ||
const resolvedData = await strategy(serverState, clientState, baseState); | ||
return new ConflictResolution_1.ConflictResolution(true, resolvedData, clientState, baseState); | ||
}; | ||
//# sourceMappingURL=handleConflictOnClient.js.map |
@@ -6,11 +6,11 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./api/ObjectConflictError")); | ||
__export(require("./api/ConflictResolution")); | ||
// State implementations | ||
__export(require("./states/VersionedObjectState")); | ||
__export(require("./states/HashObjectState")); | ||
// Strategy implementations | ||
__export(require("./strategies")); | ||
// Default API state handler | ||
var VersionedObjectState_1 = require("./states/VersionedObjectState"); | ||
exports.conflictHandler = VersionedObjectState_1.versionStateHandler; | ||
// Conflict handlers | ||
__export(require("./conflictHandlers/handleConflictOnClient")); | ||
//# sourceMappingURL=index.js.map |
@@ -0,21 +1,18 @@ | ||
import { ConflictLogger } from '../api/ConflictLogger'; | ||
import { ConflictResolution } from '../api/ConflictResolution'; | ||
import { ConflictResolutionStrategy } from '../api/ConflictResolutionStrategy'; | ||
import { ObjectState } from '../api/ObjectState'; | ||
import { ObjectStateData } from '../api/ObjectStateData'; | ||
/** | ||
* Object state manager using a hash field on object | ||
* Detects conflicts and allows moving to next state using the hash field of the object | ||
* | ||
* HashObjectState requires GraphQL types to contain hash field. | ||
* For example: | ||
* | ||
* type User { | ||
* id: ID! | ||
* hash: String | ||
* } | ||
* Object state manager using a hashing method provided by user | ||
*/ | ||
export declare class HashObjectState implements ObjectState { | ||
private hash; | ||
private logger; | ||
private hash; | ||
constructor(hashImpl: (object: any) => string); | ||
hasConflict(serverData: ObjectStateData, clientData: ObjectStateData): boolean; | ||
nextState(currentObjectState: ObjectStateData): any; | ||
resolveOnClient(serverState: ObjectStateData, clientState: ObjectStateData): ConflictResolution; | ||
resolveOnServer(strategy: ConflictResolutionStrategy, serverState: ObjectStateData, clientState: ObjectStateData): Promise<ConflictResolution>; | ||
enableLogging(logger: ConflictLogger): void; | ||
} |
"use strict"; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const debug = __importStar(require("debug")); | ||
const constants_1 = require("../constants"); | ||
const ConflictResolution_1 = require("../api/ConflictResolution"); | ||
/** | ||
* Object state manager using a hash field on object | ||
* Detects conflicts and allows moving to next state using the hash field of the object | ||
* | ||
* HashObjectState requires GraphQL types to contain hash field. | ||
* For example: | ||
* | ||
* type User { | ||
* id: ID! | ||
* hash: String | ||
* } | ||
* Object state manager using a hashing method provided by user | ||
*/ | ||
class HashObjectState { | ||
constructor(hashImpl) { | ||
this.logger = debug.default(constants_1.CONFLICT_LOGGER); | ||
this.hash = hashImpl; | ||
} | ||
hasConflict(serverData, clientData) { | ||
if (serverData.hash && clientData.hash) { | ||
if (serverData.hash !== clientData.hash) { | ||
this.logger(`Conflict when saving data. current: ${serverData}, client: ${clientData}`); | ||
return true; | ||
if (this.hash(serverData) !== this.hash(clientData)) { | ||
if (this.logger) { | ||
this.logger.info(`Conflict when saving data. | ||
current: ${JSON.stringify(serverData)}, | ||
client: ${JSON.stringify(clientData)}`); | ||
} | ||
return true; | ||
} | ||
@@ -39,8 +23,21 @@ return false; | ||
nextState(currentObjectState) { | ||
this.logger(`Moving object to next state, ${currentObjectState}`); | ||
currentObjectState.hash = this.hash(currentObjectState); | ||
// Hash can be calculated at any time and it is not added to object | ||
return currentObjectState; | ||
} | ||
resolveOnClient(serverState, clientState) { | ||
return new ConflictResolution_1.ConflictResolution(false, serverState, clientState); | ||
} | ||
async resolveOnServer(strategy, serverState, clientState) { | ||
let resolvedState = strategy(serverState, clientState); | ||
if (resolvedState instanceof Promise) { | ||
resolvedState = await resolvedState; | ||
} | ||
resolvedState = this.nextState(resolvedState); | ||
return new ConflictResolution_1.ConflictResolution(true, resolvedState, clientState); | ||
} | ||
enableLogging(logger) { | ||
this.logger = logger; | ||
} | ||
} | ||
exports.HashObjectState = HashObjectState; | ||
//# sourceMappingURL=HashObjectState.js.map |
@@ -0,1 +1,4 @@ | ||
import { ConflictLogger } from '../api/ConflictLogger'; | ||
import { ConflictResolution } from '../api/ConflictResolution'; | ||
import { ConflictResolutionStrategy } from '../api/ConflictResolutionStrategy'; | ||
import { ObjectState } from '../api/ObjectState'; | ||
@@ -19,2 +22,5 @@ import { ObjectStateData } from '../api/ObjectStateData'; | ||
nextState(currentObjectState: ObjectStateData): any; | ||
resolveOnClient(serverState: ObjectStateData, clientState: ObjectStateData): ConflictResolution; | ||
resolveOnServer(strategy: ConflictResolutionStrategy, serverState: ObjectStateData, clientState: ObjectStateData): Promise<ConflictResolution>; | ||
enableLogging(logger: ConflictLogger): void; | ||
} | ||
@@ -21,0 +27,0 @@ /** |
"use strict"; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const debug = __importStar(require("debug")); | ||
const constants_1 = require("../constants"); | ||
const ConflictResolution_1 = require("../api/ConflictResolution"); | ||
/** | ||
@@ -25,19 +17,43 @@ * Object state manager using a version field | ||
class VersionedObjectState { | ||
constructor() { | ||
this.logger = debug.default(constants_1.CONFLICT_LOGGER); | ||
} | ||
hasConflict(serverData, clientData) { | ||
if (serverData.version && clientData.version) { | ||
if (serverData.version !== clientData.version) { | ||
this.logger(`Conflict when saving data. current: ${serverData}, client: ${clientData}`); | ||
if (this.logger) { | ||
this.logger.info(`Conflict when saving data. | ||
current: ${JSON.stringify(serverData)}, | ||
client: ${JSON.stringify(clientData)}`); | ||
} | ||
return true; | ||
} | ||
} | ||
else if (this.logger) { | ||
this.logger.info(`Supplied object is missing version field required to determine conflict | ||
server: ${JSON.stringify(serverData)} | ||
client: ${JSON.stringify(clientData)}`); | ||
} | ||
return false; | ||
} | ||
nextState(currentObjectState) { | ||
this.logger(`Moving object to next state, ${currentObjectState}`); | ||
if (this.logger) { | ||
this.logger.info(`Moving object to next state, | ||
${JSON.stringify(currentObjectState)}`); | ||
} | ||
currentObjectState.version = currentObjectState.version + 1; | ||
return currentObjectState; | ||
} | ||
resolveOnClient(serverState, clientState) { | ||
return new ConflictResolution_1.ConflictResolution(false, serverState, clientState); | ||
} | ||
async resolveOnServer(strategy, serverState, clientState) { | ||
let resolvedState = strategy(serverState, clientState); | ||
if (resolvedState instanceof Promise) { | ||
resolvedState = await resolvedState; | ||
} | ||
resolvedState.version = serverState.version; | ||
resolvedState = this.nextState(resolvedState); | ||
return new ConflictResolution_1.ConflictResolution(true, resolvedState, clientState); | ||
} | ||
enableLogging(logger) { | ||
this.logger = logger; | ||
} | ||
} | ||
@@ -44,0 +60,0 @@ exports.VersionedObjectState = VersionedObjectState; |
{ | ||
"name": "@aerogear/apollo-voyager-conflicts", | ||
"version": "0.1.0-alpha", | ||
"version": "0.2.7-SNAPSHOT", | ||
"description": "A package to provide conflict handler framework for GraphQL server", | ||
@@ -25,3 +25,2 @@ "main": "dist/index.js", | ||
"@types/chai": "^4.1.3", | ||
"@types/debug": "0.0.31", | ||
"ava": "1.0.0-rc.2", | ||
@@ -33,5 +32,2 @@ "chai": "^4.1.2", | ||
}, | ||
"dependencies": { | ||
"debug": "^4.1.0" | ||
}, | ||
"publishConfig": { | ||
@@ -38,0 +34,0 @@ "access": "public" |
@@ -0,1 +1,4 @@ | ||
import { ConflictLogger } from './ConflictLogger' | ||
import { ConflictResolution } from './ConflictResolution' | ||
import { ConflictResolutionStrategy } from './ConflictResolutionStrategy' | ||
import { ObjectStateData } from './ObjectStateData' | ||
@@ -13,12 +16,32 @@ | ||
* | ||
* @param serverData the data currently on the server | ||
* @param clientData the data the client wishes to perform some mutation with | ||
* @param serverState the data currently on the server | ||
* @param clientState the data the client wishes to perform some mutation with | ||
*/ | ||
hasConflict(serverData: ObjectStateData, clientData: ObjectStateData): boolean | ||
hasConflict(serverState: ObjectStateData, clientState: ObjectStateData): boolean | ||
/** | ||
* | ||
* @param currentObjectState the object wish you would like to progress to its next state | ||
* @param objectState the object wish you would like to progress to its next state | ||
*/ | ||
nextState(currentObjectState: ObjectStateData): ObjectStateData | ||
nextState(objectState: ObjectStateData): ObjectStateData | ||
/** | ||
* | ||
* @param serverState the current state of the object on the server | ||
* @param clientState the state of the object the client wishes to perform some mutation with | ||
*/ | ||
resolveOnClient(serverState: ObjectStateData, clientState: ObjectStateData): ConflictResolution | ||
/** | ||
* | ||
* @param serverState the current state of the object on the server | ||
* @param clientState the state of the object the client wishes to perform some mutation with | ||
*/ | ||
resolveOnServer (strategy: ConflictResolutionStrategy, serverState: ObjectStateData, clientState: ObjectStateData): Promise<ConflictResolution> | ||
/** | ||
* Enable logging for conflict resolution package | ||
* @param logger - logger implementation | ||
*/ | ||
enableLogging(logger: ConflictLogger): void | ||
} |
// Conflict api | ||
export * from './api/ObjectState' | ||
export * from './api/ObjectConflictError' | ||
export * from './api/ConflictResolution' | ||
export * from './api/ObjectStateData' | ||
export * from './api/ConflictLogger' | ||
@@ -9,7 +10,8 @@ // State implementations | ||
export * from './states/HashObjectState' | ||
// Strategy implementations | ||
export * from './strategies' | ||
// Default API state handler | ||
export { versionStateHandler as conflictHandler } | ||
from './states/VersionedObjectState' | ||
// Conflict handlers | ||
export * from './conflictHandlers/handleConflictOnClient' |
@@ -1,21 +0,13 @@ | ||
import * as debug from 'debug' | ||
import { ConflictLogger } from '../api/ConflictLogger' | ||
import { ConflictResolution } from '../api/ConflictResolution' | ||
import { ConflictResolutionStrategy } from '../api/ConflictResolutionStrategy' | ||
import { ObjectState } from '../api/ObjectState' | ||
import { ObjectStateData } from '../api/ObjectStateData' | ||
import { CONFLICT_LOGGER } from '../constants' | ||
/** | ||
* Object state manager using a hash field on object | ||
* Detects conflicts and allows moving to next state using the hash field of the object | ||
* | ||
* HashObjectState requires GraphQL types to contain hash field. | ||
* For example: | ||
* | ||
* type User { | ||
* id: ID! | ||
* hash: String | ||
* } | ||
* Object state manager using a hashing method provided by user | ||
*/ | ||
export class HashObjectState implements ObjectState { | ||
private logger = debug.default(CONFLICT_LOGGER) | ||
private hash: (object: any) => string | ||
private logger: ConflictLogger | undefined | ||
@@ -27,8 +19,9 @@ constructor(hashImpl: (object: any) => string) { | ||
public hasConflict(serverData: ObjectStateData, clientData: ObjectStateData) { | ||
if (serverData.hash && clientData.hash) { | ||
if (serverData.hash !== clientData.hash) { | ||
this.logger(`Conflict when saving data. current: ${serverData}, client: ${clientData}`) | ||
return true | ||
if (this.hash(serverData) !== this.hash(clientData)) { | ||
if (this.logger) { | ||
this.logger.info(`Conflict when saving data. | ||
current: ${ JSON.stringify(serverData)}, | ||
client: ${JSON.stringify(clientData)}`) | ||
} | ||
return true | ||
} | ||
@@ -39,6 +32,26 @@ return false | ||
public nextState(currentObjectState: ObjectStateData) { | ||
this.logger(`Moving object to next state, ${currentObjectState}`) | ||
currentObjectState.hash = this.hash(currentObjectState) | ||
// Hash can be calculated at any time and it is not added to object | ||
return currentObjectState | ||
} | ||
public resolveOnClient(serverState: ObjectStateData, clientState: ObjectStateData) { | ||
return new ConflictResolution(false, serverState, clientState) | ||
} | ||
public async resolveOnServer(strategy: ConflictResolutionStrategy, serverState: ObjectStateData, clientState: ObjectStateData) { | ||
let resolvedState = strategy(serverState, clientState) | ||
if (resolvedState instanceof Promise) { | ||
resolvedState = await resolvedState | ||
} | ||
resolvedState = this.nextState(resolvedState) | ||
return new ConflictResolution(true, resolvedState, clientState) | ||
} | ||
public enableLogging(logger: ConflictLogger): void { | ||
this.logger = logger | ||
} | ||
} |
@@ -1,5 +0,6 @@ | ||
import * as debug from 'debug' | ||
import { ConflictLogger } from '../api/ConflictLogger' | ||
import { ConflictResolution } from '../api/ConflictResolution' | ||
import { ConflictResolutionStrategy } from '../api/ConflictResolutionStrategy' | ||
import { ObjectState } from '../api/ObjectState' | ||
import { ObjectStateData } from '../api/ObjectStateData' | ||
import { CONFLICT_LOGGER } from '../constants' | ||
@@ -19,3 +20,3 @@ /** | ||
export class VersionedObjectState implements ObjectState { | ||
private logger = debug.default(CONFLICT_LOGGER) | ||
private logger: ConflictLogger | undefined | ||
@@ -25,5 +26,14 @@ public hasConflict(serverData: ObjectStateData, clientData: ObjectStateData) { | ||
if (serverData.version !== clientData.version) { | ||
this.logger(`Conflict when saving data. current: ${serverData}, client: ${clientData}`) | ||
if (this.logger) { | ||
this.logger.info(`Conflict when saving data. | ||
current: ${ JSON.stringify(serverData)}, | ||
client: ${JSON.stringify(clientData)}`) | ||
} | ||
return true | ||
} | ||
} else if (this.logger) { | ||
this.logger.info( | ||
`Supplied object is missing version field required to determine conflict | ||
server: ${JSON.stringify(serverData)} | ||
client: ${JSON.stringify(clientData)}`) | ||
} | ||
@@ -34,6 +44,30 @@ return false | ||
public nextState(currentObjectState: ObjectStateData) { | ||
this.logger(`Moving object to next state, ${currentObjectState}`) | ||
if (this.logger) { | ||
this.logger.info(`Moving object to next state, | ||
${JSON.stringify(currentObjectState)}`) | ||
} | ||
currentObjectState.version = currentObjectState.version + 1 | ||
return currentObjectState | ||
} | ||
public resolveOnClient(serverState: ObjectStateData, clientState: ObjectStateData) { | ||
return new ConflictResolution(false, serverState, clientState) | ||
} | ||
public async resolveOnServer(strategy: ConflictResolutionStrategy, serverState: ObjectStateData, clientState: ObjectStateData) { | ||
let resolvedState = strategy(serverState, clientState) | ||
if (resolvedState instanceof Promise) { | ||
resolvedState = await resolvedState | ||
} | ||
resolvedState.version = serverState.version | ||
resolvedState = this.nextState(resolvedState) | ||
return new ConflictResolution(true, resolvedState, clientState) | ||
} | ||
public enableLogging(logger: ConflictLogger): void { | ||
this.logger = logger | ||
} | ||
} | ||
@@ -40,0 +74,0 @@ |
import test from 'ava' | ||
import { VersionedObjectState } from '../src' | ||
import { VersionedObjectState, ObjectStateData } from '../src' | ||
import { ObjectConflictError } from '../src/api/ConflictResolution' | ||
import { strategies } from '../src/strategies' | ||
@@ -19,7 +21,213 @@ test('With conflict', (t) => { | ||
test('Next state ', (t) => { | ||
test('Missing version', (t) => { | ||
const objectState = new VersionedObjectState() | ||
const serverData = { name: 'AeroGear'} | ||
const clientData = { name: 'AeroGear', version: 1 } | ||
t.deepEqual(objectState.hasConflict(serverData, clientData), false) | ||
}) | ||
test('Next state ', async (t) => { | ||
const serverData = { name: 'AeroGear', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
objectState.nextState(serverData) | ||
t.deepEqual(serverData.version, 2) | ||
const next = await objectState.nextState(serverData) | ||
t.deepEqual(next.version, 2) | ||
}) | ||
test('resolveOnClient returns the expected conflict payload for the client', (t) => { | ||
const serverState = { name: 'AeroGear', version: 2 } | ||
const clientState = { name: 'AeroGear Client', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
const resolution = objectState.resolveOnClient(serverState, clientState) | ||
const expected = { | ||
payload: new ObjectConflictError({ | ||
serverState, | ||
clientState, | ||
resolvedOnServer: false | ||
}) | ||
} | ||
t.falsy(resolution.resolvedState) | ||
t.truthy(resolution.payload) | ||
t.deepEqual(resolution.payload, expected.payload) | ||
}) | ||
test('resolveOnServer works with the client wins strategy', async (t) => { | ||
const serverState = { name: 'AeroGear', version: 2 } | ||
const clientState = { name: 'Client', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
const strategy = strategies.clientWins | ||
const resolution = await objectState.resolveOnServer(strategy, serverState, clientState) | ||
const expectedResolvedState = { | ||
name: 'Client' , | ||
version: 3 | ||
} | ||
const expected = { | ||
resolvedState: expectedResolvedState, | ||
payload: new ObjectConflictError({ | ||
serverState: expectedResolvedState, | ||
clientState, | ||
resolvedOnServer: true | ||
}) | ||
} | ||
t.truthy(resolution.resolvedState) | ||
t.truthy(resolution.payload) | ||
t.deepEqual(resolution.resolvedState, expected.resolvedState) | ||
t.deepEqual(resolution.payload, expected.payload) | ||
}) | ||
test('resolveOnServer works with the server wins strategy', async (t) => { | ||
const serverState = { name: 'AeroGear', version: 2 } | ||
const clientState = { name: 'Client', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
const strategy = strategies.serverWins | ||
const resolution = await objectState.resolveOnServer(strategy, serverState, clientState) | ||
const expectedResolvedState = { | ||
name: 'AeroGear' , | ||
version: 3 | ||
} | ||
const expected = { | ||
resolvedState: expectedResolvedState, | ||
payload: new ObjectConflictError({ | ||
serverState: expectedResolvedState, | ||
clientState, | ||
resolvedOnServer: true | ||
}) | ||
} | ||
t.truthy(resolution.resolvedState) | ||
t.truthy(resolution.payload) | ||
t.deepEqual(resolution.resolvedState, expected.resolvedState) | ||
t.deepEqual(resolution.payload, expected.payload) | ||
}) | ||
test('resolveOnServer resolves the data using a custom handler', async (t) => { | ||
const serverState = { name: 'AeroGear', version: 2 } | ||
const clientState = { name: 'Client', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
function customStrategy(serverState: ObjectStateData, clientState: ObjectStateData) { | ||
return { | ||
name: `${serverState.name} ${clientState.name}` | ||
} | ||
} | ||
const resolution = await objectState.resolveOnServer(customStrategy, serverState, clientState) | ||
const expectedResolvedState = { | ||
name: 'AeroGear Client' , | ||
version: 3 | ||
} | ||
const expected = { | ||
resolvedState: expectedResolvedState, | ||
payload: new ObjectConflictError({ | ||
serverState: expectedResolvedState, | ||
clientState, | ||
resolvedOnServer: true | ||
}) | ||
} | ||
t.truthy(resolution.resolvedState) | ||
t.truthy(resolution.payload) | ||
t.deepEqual(resolution.resolvedState, expected.resolvedState) | ||
t.deepEqual(resolution.payload, expected.payload) | ||
}) | ||
test('resolveOnServer applies the correct version number to resolvedState', async (t) => { | ||
const serverState = { name: 'AeroGear', version: 2 } | ||
const clientState = { name: 'Client', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
function customStrategy(serverState: ObjectStateData, clientState: ObjectStateData) { | ||
return { | ||
name: `${serverState.name} ${clientState.name}`, | ||
version: 50 // this gets overwritten with the correct version | ||
} | ||
} | ||
const resolution = await objectState.resolveOnServer(customStrategy, serverState, clientState) | ||
const expectedResolvedState = { | ||
name: 'AeroGear Client' , | ||
version: 3 | ||
} | ||
const expected = { | ||
resolvedState: expectedResolvedState, | ||
payload: new ObjectConflictError({ | ||
serverState: expectedResolvedState, | ||
clientState, | ||
resolvedOnServer: true | ||
}) | ||
} | ||
t.truthy(resolution.resolvedState) | ||
t.truthy(resolution.payload) | ||
t.deepEqual(resolution.resolvedState, expected.resolvedState) | ||
t.deepEqual(resolution.payload, expected.payload) | ||
}) | ||
test('resolveOnServer resolves the data using a custom async handler', async (t) => { | ||
const serverState = { name: 'AeroGear', version: 2 } | ||
const clientState = { name: 'Client', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
function customStrategy(serverState: ObjectStateData, clientState: ObjectStateData) { | ||
return new Promise((resolve, reject) => { | ||
return resolve({ | ||
name: `${serverState.name} ${clientState.name}` | ||
}) | ||
}) | ||
} | ||
const resolution = await objectState.resolveOnServer(customStrategy, serverState, clientState) | ||
const expectedResolvedState = { | ||
name: 'AeroGear Client' , | ||
version: 3 | ||
} | ||
const expected = { | ||
resolvedState: expectedResolvedState, | ||
payload: new ObjectConflictError({ | ||
serverState: expectedResolvedState, | ||
clientState, | ||
resolvedOnServer: true | ||
}) | ||
} | ||
t.truthy(resolution.resolvedState) | ||
t.truthy(resolution.payload) | ||
t.deepEqual(resolution.resolvedState, expected.resolvedState) | ||
t.deepEqual(resolution.payload, expected.payload) | ||
}) | ||
test('resolveOnServer throws if custom async strategy rejects', async (t) => { | ||
const serverState = { name: 'AeroGear', version: 2 } | ||
const clientState = { name: 'Client', version: 1 } | ||
const objectState = new VersionedObjectState() | ||
function customStrategy(serverState: ObjectStateData, clientState: ObjectStateData) { | ||
return new Promise((resolve, reject) => { | ||
return reject(new Error('an error occurred')) | ||
}) | ||
} | ||
await t.throwsAsync(async () => { | ||
await objectState.resolveOnServer(customStrategy, serverState, clientState) | ||
}) | ||
}) | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45517
0
6
59
956
1
- Removeddebug@^4.1.0
- Removeddebug@4.3.7(transitive)
- Removedms@2.1.3(transitive)