Skip to content

Commit

Permalink
Add JsonApiCondition (#550)
Browse files Browse the repository at this point in the history
  • Loading branch information
KPrasch committed Jul 31, 2024
2 parents 3f15a7f + 30ab3c3 commit f7c1514
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 0 deletions.
28 changes: 28 additions & 0 deletions packages/taco/src/conditions/base/json-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { z } from 'zod';

import { Condition } from '../condition';
import {
OmitConditionType,
returnValueTestSchema,
} from '../shared';

export const JsonApiConditionType = 'json-api';

export const JsonApiConditionSchema = z.object({
conditionType: z.literal(JsonApiConditionType).default(JsonApiConditionType),
endpoint: z.string().url(),
parameters: z.record(z.string(), z.unknown()).optional(),
query: z.string().optional(),
returnValueTest: returnValueTestSchema, // Update to allow multiple return values after expanding supported methods
});

export type JsonApiConditionProps = z.infer<typeof JsonApiConditionSchema>;

export class JsonApiCondition extends Condition {
constructor(value: OmitConditionType<JsonApiConditionProps>) {
super(JsonApiConditionSchema, {
conditionType: JsonApiConditionType,
...value,
});
}
}
7 changes: 7 additions & 0 deletions packages/taco/src/conditions/condition-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import {
ContractConditionProps,
ContractConditionType,
} from './base/contract';
import {
JsonApiCondition,
JsonApiConditionProps,
JsonApiConditionType,
} from './base/json-api';
import { RpcCondition, RpcConditionProps, RpcConditionType } from './base/rpc';
import {
TimeCondition,
Expand Down Expand Up @@ -30,6 +35,8 @@ export class ConditionFactory {
return new ContractCondition(props as ContractConditionProps);
case CompoundConditionType:
return new CompoundCondition(props as CompoundConditionProps);
case JsonApiConditionType:
return new JsonApiCondition(props as JsonApiConditionProps);
default:
throw new Error(ERR_INVALID_CONDITION_TYPE(props.conditionType));
}
Expand Down
63 changes: 63 additions & 0 deletions packages/taco/test/conditions/base/json.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { describe, expect, it } from 'vitest';

import {
JsonApiCondition,
JsonApiConditionSchema,
} from '../../../src/conditions/base/json-api';
import { testJsonApiConditionObj } from '../../test-utils';

describe('JsonApiCondition', () => {
describe('validation', () => {
it('accepts a valid schema', () => {
const result = JsonApiCondition.validate(
JsonApiConditionSchema,
testJsonApiConditionObj,
);

expect(result.error).toBeUndefined();
expect(result.data).toEqual(testJsonApiConditionObj);
});

it('rejects an invalid schema', () => {
const badJsonApiObj = {
...testJsonApiConditionObj,
endpoint: 'not-a-url',
};

const result = JsonApiCondition.validate(JsonApiConditionSchema, badJsonApiObj);

expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
expect(result.error?.format()).toMatchObject({
endpoint: {
_errors: ['Invalid url'],
},
});
});

describe('parameters', () => {
it('accepts conditions without query path', () => {
const { query, ...noQueryObj} = testJsonApiConditionObj;
const result = JsonApiCondition.validate(
JsonApiConditionSchema,
noQueryObj
);

expect(result.error).toBeUndefined();
expect(result.data).toEqual(noQueryObj);
});

it('accepts conditions without parameters', () => {
const { query, ...noParamsObj} = testJsonApiConditionObj;
const result = JsonApiCondition.validate(
JsonApiConditionSchema,
noParamsObj
);

expect(result.error).toBeUndefined();
expect(result.data).toEqual(noParamsObj);
});
});
});
});
20 changes: 20 additions & 0 deletions packages/taco/test/conditions/condition-expr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ContractCondition,
ContractConditionProps,
} from '../../src/conditions/base/contract';
import { JsonApiCondition } from '../../src/conditions/base/json-api';
import { RpcCondition, RpcConditionType } from '../../src/conditions/base/rpc';
import {
TimeCondition,
Expand All @@ -20,6 +21,7 @@ import { ERC721Balance } from '../../src/conditions/predefined/erc721';
import {
testContractConditionObj,
testFunctionAbi,
testJsonApiConditionObj,
testReturnValueTest,
testRpcConditionObj,
testTimeConditionObj,
Expand Down Expand Up @@ -56,6 +58,7 @@ describe('condition set', () => {

const rpcCondition = new RpcCondition(testRpcConditionObj);
const timeCondition = new TimeCondition(testTimeConditionObj);
const jsonApiCondition = new JsonApiCondition(testJsonApiConditionObj);
const compoundCondition = new CompoundCondition({
operator: 'and',
operands: [
Expand Down Expand Up @@ -401,6 +404,23 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(RpcCondition);
});

it('json api condition serialization', () => {
const conditionExpr = new ConditionExpression(jsonApiCondition);

const conditionExprJson = conditionExpr.toJson();
expect(conditionExprJson).toBeDefined();
expect(conditionExprJson).toContain('endpoint');
expect(conditionExprJson).toContain('https://_this_would_totally_fail.com');
expect(conditionExprJson).toContain('parameters');
expect(conditionExprJson).toContain('query');
expect(conditionExprJson).toContain('$.ethereum.usd');
expect(conditionExprJson).toContain('returnValueTest');

const conditionExprFromJson = ConditionExpression.fromJSON(conditionExprJson);
expect(conditionExprFromJson).toBeDefined();
expect(conditionExprFromJson.condition).toBeInstanceOf(JsonApiCondition);
});

it('compound condition serialization', () => {
const conditionExpr = new ConditionExpression(compoundCondition);
const compoundConditionObj = compoundCondition.toObj();
Expand Down
15 changes: 15 additions & 0 deletions packages/taco/test/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ import {
ContractConditionType,
FunctionAbiProps,
} from '../src/conditions/base/contract';
import {
JsonApiConditionProps,
JsonApiConditionType
} from '../src/conditions/base/json-api';
import {
RpcConditionProps,
RpcConditionType,
Expand Down Expand Up @@ -222,6 +226,17 @@ export const testTimeConditionObj: TimeConditionProps = {
chain: TEST_CHAIN_ID,
};

export const testJsonApiConditionObj = {
conditionType: JsonApiConditionType,
endpoint: 'https://_this_would_totally_fail.com',
parameters: {
'ids': 'ethereum',
'vs_currencies': 'usd',
},
query: '$.ethereum.usd',
returnValueTest: testReturnValueTest,
};

export const testRpcConditionObj: RpcConditionProps = {
conditionType: RpcConditionType,
chain: TEST_CHAIN_ID,
Expand Down

0 comments on commit f7c1514

Please sign in to comment.