Skip to content

Commit

Permalink
apply & refactor jellyfish-json consumers
Browse files Browse the repository at this point in the history
  • Loading branch information
fuxingloh committed Apr 16, 2021
1 parent e5697a9 commit bb91e5e
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { JellyfishJSON, ApiClient, Precision, RpcApiError } from '../src'
import { ApiClient, RpcApiError } from '../src'
import { DeFiDContainer } from '@defichain/testcontainers'
import { JellyfishJSON, Precision, PrecisionPath } from '@defichain/jellyfish-json'

/**
* Jellyfish client adapter for container
Expand All @@ -16,7 +17,7 @@ export class ContainerAdapterClient extends ApiClient {
/**
* Wrap the call from client to testcontainers.
*/
async call<T> (method: string, params: any[], precision: Precision): Promise<T> {
async call<T> (method: string, params: any[], precision: Precision | PrecisionPath): Promise<T> {
const body = JellyfishJSON.stringify({
jsonrpc: '1.0',
id: Math.floor(Math.random() * 100000000000000),
Expand All @@ -25,9 +26,9 @@ export class ContainerAdapterClient extends ApiClient {
})

const text = await this.container.post(body)
const response = JellyfishJSON.parse(text, precision)

const { result, error } = response
const { result, error } = JellyfishJSON.parse(text, {
result: precision
})

if (error !== undefined && error !== null) {
throw new RpcApiError(error)
Expand Down
6 changes: 5 additions & 1 deletion packages/jellyfish-api-core/src/category/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ export class Blockchain {
* @return Promise<UTXODetails>
*/
async getTxOut (txId: string, index: number, includeMempool = true): Promise<UTXODetails> {
return await this.client.call('gettxout', [txId, index, includeMempool], { value: 'bignumber' })
return await this.client.call('gettxout', [
txId, index, includeMempool
], {
value: 'bignumber'
})
}
}

Expand Down
9 changes: 6 additions & 3 deletions packages/jellyfish-api-jsonrpc/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import fetch from 'cross-fetch'
import { Response } from 'cross-fetch/lib.fetch'
import AbortController from 'abort-controller'
import { PrecisionPath } from '@defichain/jellyfish-json'

/**
* ClientOptions for JsonRpc
Expand Down Expand Up @@ -58,7 +59,7 @@ export class JsonRpcClient extends ApiClient {
/**
* Implements JSON-RPC 1.0 specification for ApiClient
*/
async call<T> (method: string, params: any[], precision: Precision): Promise<T> {
async call<T> (method: string, params: any[], precision: Precision | PrecisionPath): Promise<T> {
const body = JsonRpcClient.stringify(method, params)
const response = await this.fetchTimeout(body)
const text = await response.text()
Expand All @@ -83,8 +84,10 @@ export class JsonRpcClient extends ApiClient {
})
}

private static parse (text: string, precision: Precision): any {
const { result, error } = JellyfishJSON.parse(text, precision)
private static parse (text: string, precision: Precision | PrecisionPath): any {
const { result, error } = JellyfishJSON.parse(text, {
result: precision
})

if (error !== undefined && error !== null) {
throw new RpcApiError(error)
Expand Down
60 changes: 58 additions & 2 deletions packages/jellyfish-json/__tests__/remap.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parse } from 'lossless-json'
import { LosslessNumber, parse } from 'lossless-json'
import { PrecisionPath, remap } from '../src/remap'
import { BigNumber } from '../src'

Expand Down Expand Up @@ -145,8 +145,28 @@ describe('remap individually', () => {
})
})

it('should remap lossless | number | bignumber', () => {
const parsed = parseAndRemap(`{
"a": 1,
"b": 2,
"c": 3
}`, {
a: 'bignumber',
b: 'lossless',
c: 'number'
})

expect(parsed.a instanceof BigNumber).toBe(true)
expect(parsed.a.toString()).toBe('1')

expect(parsed.b instanceof LosslessNumber).toBe(true)
expect(parsed.b.toString()).toBe('2')

expect(parsed.c).toBe(3)
})

describe('remap invalid mapping should succeed', () => {
it('should ignore invalid remapping', () => {
it('should ignore invalid mapping', () => {
const parsed = parseAndRemap(`{
"ignored": 123.4,
"num": 1000
Expand All @@ -158,4 +178,40 @@ describe('remap invalid mapping should succeed', () => {
expect(parsed.ignored).toBe(123.4)
expect(parsed.num).toBe(1000)
})

it('should ignore invalid null object', () => {
remap({
invalid: null
}, {
invalid: 'bignumber'
})
})

it('should ignore invalid undefined object', () => {
remap({
invalid: undefined
}, {
invalid: 'bignumber'
})
})

it('should ignore invalid null mapping', () => {
parseAndRemap(`{
"invalid": 123.4,
"num": 1000
}`, {
// @ts-expect-error
invalid: undefined
})
})

it('should ignore invalid undefined mapping', () => {
parseAndRemap(`{
"invalid": 123.4,
"num": 1000
}`, {
// @ts-expect-error
invalid: undefined
})
})
})
43 changes: 30 additions & 13 deletions packages/jellyfish-json/src/remap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import BigNumber from 'bignumber.js'
import { LosslessNumber } from 'lossless-json'
import { Precision } from './index'

/**
* Path based precision mapping
Expand All @@ -26,7 +27,7 @@ import { LosslessNumber } from 'lossless-json'
* }
*/
export interface PrecisionPath {
[path: string]: 'bignumber' | PrecisionPath
[path: string]: Precision | PrecisionPath
}

/**
Expand All @@ -41,50 +42,66 @@ export function remap (losslessObj: any, precision: PrecisionPath): any {
* @param {any} losslessObj to deeply remap
* @param {'bignumber' | PrecisionPath} precision path mapping
*/
function deepRemap (losslessObj: any, precision: 'bignumber' | PrecisionPath): any {
function deepRemap (losslessObj: any, precision: Precision | PrecisionPath): any {
if (losslessObj === null || losslessObj === undefined) {
return losslessObj
}

if (typeof precision !== 'object') {
return reviveObjectAs(losslessObj, precision)
return reviveAs(losslessObj, precision)
}

if (Array.isArray(losslessObj)) {
return losslessObj.map(obj => deepRemap(obj, precision))
}

if (losslessObj instanceof LosslessNumber) {
return reviveLosslessAs(losslessObj)
}

for (const [key, value] of Object.entries(losslessObj)) {
losslessObj[key] = deepRemap(value, precision[key])
}
return reviveObjectAs(losslessObj)
return losslessObj
}

/**
* Array will deeply remapped, object keys will be iterated on.
* Array will deeply remapped, object keys will be iterated on as keys.
*
* @param {any} losslessObj to revive
* @param {'bignumber'} precision to use, specific 'bignumber' for BigNumber else always default to number
* @param precision to use, specific 'bignumber' for BigNumber or values always ignored and default to number
*/
function reviveObjectAs (losslessObj: any, precision?: 'bignumber' | string): any {
if (Array.isArray(losslessObj)) {
return losslessObj.map((v: any) => reviveObjectAs(v, precision))
function reviveAs (losslessObj: any, precision?: Precision): any {
if (losslessObj === null || losslessObj === undefined) {
return losslessObj
}

if (losslessObj instanceof LosslessNumber) {
return reviveLosslessAs(losslessObj, precision)
}

if (Array.isArray(losslessObj)) {
return losslessObj.map((v: any) => reviveAs(v, precision))
}

if (typeof losslessObj === 'object') {
for (const [key, value] of Object.entries(losslessObj)) {
losslessObj[key] = reviveObjectAs(value, precision)
losslessObj[key] = reviveAs(value, precision)
}
return losslessObj
}

return losslessObj
}

/**
* @param {LosslessNumber} losslessNum to revive as bignumber or number if precision != bignumber
* @param {'bignumber'} precision to use, specific 'bignumber' for BigNumber else always default to number
* @param {Precision} precision to use, specific 'bignumber' for BigNumber else always default to number
*/
function reviveLosslessAs (losslessNum: LosslessNumber, precision?: 'bignumber' | string): BigNumber | number {
function reviveLosslessAs (losslessNum: LosslessNumber, precision?: Precision): BigNumber | LosslessNumber | number {
if (precision === 'lossless') {
return losslessNum
}

if (precision === 'bignumber') {
return new BigNumber(losslessNum.toString())
}
Expand Down

0 comments on commit bb91e5e

Please sign in to comment.