Skip to content

Commit

Permalink
fix: manual merge
Browse files Browse the repository at this point in the history
  • Loading branch information
shuffledex committed Jul 30, 2020
2 parents 2884560 + 2da3137 commit 3054fe4
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 19 deletions.
102 changes: 97 additions & 5 deletions src/api/entities/Proposal/__tests__/index.ts
@@ -1,20 +1,26 @@
import BigNumber from 'bignumber.js';

import { Identity } from '~/api/entities/Identity';
import { Entity } from '~/base';
import { Context } from '~/context';
import { eventByIndexedArgs, proposalVotes } from '~/middleware/queries';
import { EventIdEnum, ModuleIdEnum } from '~/middleware/types';
import { dsMockUtils } from '~/testUtils/mocks';

import { Proposal } from '../';

describe('Proposal class', () => {
const pipId = 10;
let context: Context;
let proposal: Proposal;

beforeAll(() => {
dsMockUtils.initMocks();
});

beforeEach(() => {
context = dsMockUtils.getContextInstance();
proposal = new Proposal({ pipId }, context);
});

afterEach(() => {
Expand All @@ -31,18 +37,104 @@ describe('Proposal class', () => {

describe('constructor', () => {
test('should assign pipId to instance', () => {
const pipId = new BigNumber(10);
const proposal = new Proposal({ pipId }, context);

expect(proposal.pipId).toBe(pipId);
});
});

describe('method: isUniqueIdentifiers', () => {
test('should return true if the object conforms to the interface', () => {
expect(Proposal.isUniqueIdentifiers({ pipId: new BigNumber(1) })).toBe(true);
expect(Proposal.isUniqueIdentifiers({ pipId: 10 })).toBe(true);
expect(Proposal.isUniqueIdentifiers({})).toBe(false);
expect(Proposal.isUniqueIdentifiers({ pipId: 1 })).toBe(false);
expect(Proposal.isUniqueIdentifiers({ pipId: '10' })).toBe(false);
});
});

describe('method: identityHasVoted', () => {
const did = 'someDid';
const variables = {
moduleId: ModuleIdEnum.Pips,
eventId: EventIdEnum.Voted,
eventArg0: did,
eventArg2: pipId.toString(),
};

beforeEach(() => {
context = dsMockUtils.getContextInstance();
proposal = new Proposal({ pipId }, context);
});

test('should return true if the identity has voted on the proposal', async () => {
const fakeResult = true;

dsMockUtils.createApolloQueryStub(eventByIndexedArgs(variables), {
/* eslint-disable @typescript-eslint/camelcase */
eventByIndexedArgs: {
block_id: 'someBlockId',
},
/* eslint-enable @typescript-eslint/camelcase */
});

const result = await proposal.identityHasVoted();
expect(result).toEqual(fakeResult);
});

test('should return false if the identity has not voted on the proposal', async () => {
dsMockUtils.createApolloQueryStub(eventByIndexedArgs(variables), {});
const result = await proposal.identityHasVoted({ did: 'someDid' });
expect(result).toBeFalsy();
});

test('should throw if the middleware query fails', async () => {
dsMockUtils.throwOnMiddlewareQuery();

return expect(proposal.identityHasVoted()).rejects.toThrow(
'Error in middleware query: Error'
);
});
});

describe('method: getVotes', () => {
test('should return the list of votes', async () => {
const did = 'someDid';
const vote = false;
const weight = new BigNumber(10000000000);
const proposalVotesQueryResponse = [
{
account: did,
vote,
weight: weight.toNumber(),
},
];
const fakeResult = [
{
identity: new Identity({ did }, context),
vote,
weight,
},
];

dsMockUtils.createApolloQueryStub(
proposalVotes({
pipId,
vote: undefined,
orderBy: undefined,
count: undefined,
skip: undefined,
}),
{
proposalVotes: proposalVotesQueryResponse,
}
);

const result = await proposal.getVotes();

expect(result).toEqual(fakeResult);
});

test('should throw if the middleware query fails', async () => {
dsMockUtils.throwOnMiddlewareQuery();

return expect(proposal.getVotes()).rejects.toThrow('Error in middleware query: Error');
});
});
});
111 changes: 107 additions & 4 deletions src/api/entities/Proposal/index.ts
@@ -1,13 +1,21 @@
import { ApolloQueryResult } from 'apollo-client';
import BigNumber from 'bignumber.js';

import { Entity } from '~/base';
import { Identity } from '~/api/entities/Identity';
import { Entity, PolymeshError } from '~/base';
import { Context } from '~/context';
import { eventByIndexedArgs, proposalVotes } from '~/middleware/queries';
import { EventIdEnum, ModuleIdEnum, Query } from '~/middleware/types';
import { Ensured, ErrorCode, ProposalVotesOrderByInput } from '~/types';
import { valueToDid } from '~/utils';

import { ProposalVote } from './types';

/**
* Properties that uniquely identify a Proposal
*/
export interface UniqueIdentifiers {
pipId: BigNumber;
pipId: number;
}

/**
Expand All @@ -21,13 +29,13 @@ export class Proposal extends Entity<UniqueIdentifiers> {
public static isUniqueIdentifiers(identifier: unknown): identifier is UniqueIdentifiers {
const { pipId } = identifier as UniqueIdentifiers;

return pipId instanceof BigNumber;
return typeof pipId === 'number';
}

/**
* internal identifier
*/
public pipId: BigNumber;
public pipId: number;

/**
* @hidden
Expand All @@ -39,4 +47,99 @@ export class Proposal extends Entity<UniqueIdentifiers> {

this.pipId = pipId;
}

/**
* Check if an identity has voted on the proposal
*
* @param args.did - identity representation or identity ID as stored in the blockchain
*/
public async identityHasVoted(args?: { did: string | Identity }): Promise<boolean> {
const {
context: { middlewareApi },
pipId,
context,
} = this;

let identity: string;

if (args) {
identity = valueToDid(args.did);
} else {
identity = context.getCurrentIdentity().did;
}

let result: ApolloQueryResult<Ensured<Query, 'eventByIndexedArgs'>>;
try {
result = await middlewareApi.query<Ensured<Query, 'eventByIndexedArgs'>>(
eventByIndexedArgs({
moduleId: ModuleIdEnum.Pips,
eventId: EventIdEnum.Voted,
eventArg0: identity,
eventArg2: pipId.toString(),
})
);
} catch (e) {
throw new PolymeshError({
code: ErrorCode.MiddlewareError,
message: `Error in middleware query: ${e.message}`,
});
}

if (result.data.eventByIndexedArgs) {
return true;
}

return false;
}

/**
* Retrieve all the votes of the proposal. Can be filtered using parameters
*
* @param opts.vote - vote decision (positive or negative)
* @param opts.orderBy - the order in witch the votes are returned
* @param opts.size - number of votes in each requested page (default: 25)
* @param opts.start - page offset
*/
public async getVotes(
opts: {
vote?: boolean;
orderBy?: ProposalVotesOrderByInput;
size?: number;
start?: number;
} = {}
): Promise<ProposalVote[]> {
const {
context: { middlewareApi },
pipId,
context,
} = this;

const { vote, orderBy, size, start } = opts;

let result: ApolloQueryResult<Ensured<Query, 'proposalVotes'>>;
try {
result = await middlewareApi.query<Ensured<Query, 'proposalVotes'>>(
proposalVotes({
pipId,
vote,
orderBy,
count: size,
skip: start,
})
);
} catch (e) {
throw new PolymeshError({
code: ErrorCode.MiddlewareError,
message: `Error in middleware query: ${e.message}`,
});
}

return result.data.proposalVotes.map(({ account: did, vote: proposalVote, weight }) => {
return {
identity: new Identity({ did }, context),
vote: proposalVote,
weight: new BigNumber(weight),
};
});
}
}
6 changes: 6 additions & 0 deletions src/api/entities/Proposal/types.ts
Expand Up @@ -33,6 +33,12 @@ export interface Metadata {
totalVotes: number;
}

export interface ProposalVote {
identity: Identity;
vote: boolean;
weight: BigNumber;
}

export enum ProposalState {
Pending = 'Pending',
Cancelled = 'Cancelled',
Expand Down
6 changes: 3 additions & 3 deletions src/api/procedures/__tests__/createProposal.ts
Expand Up @@ -185,11 +185,11 @@ describe('createProposal procedure', () => {

describe('createPrroposalResolver', () => {
const findEventRecordStub = sinon.stub(utilsModule, 'findEventRecord');
const pipId = new BigNumber(1);
const rawPipId = dsMockUtils.createMockU32(pipId.toNumber());
const pipId = 1;
const rawPipId = dsMockUtils.createMockU32(pipId);

beforeAll(() => {
entityMockUtils.initMocks({ proposalOptions: { pipId: new BigNumber(pipId) } });
entityMockUtils.initMocks({ proposalOptions: { pipId } });
});

beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/api/procedures/createProposal.ts
Expand Up @@ -33,7 +33,7 @@ export const createProposalResolver = (context: Context) => (
const data = eventRecord.event.data;
const pipId = u32ToBigNumber(data[2] as PipId);

return new Proposal({ pipId }, context);
return new Proposal({ pipId: pipId.toNumber() }, context);
};

/**
Expand Down
30 changes: 28 additions & 2 deletions src/middleware/__tests__/queries.ts
@@ -1,6 +1,32 @@
import { ClaimTypeEnum, EventIdEnum, ModuleIdEnum } from '~/middleware/types';
import {
ClaimTypeEnum,
EventIdEnum,
ModuleIdEnum,
Order,
ProposalVotesOrderFields,
} from '~/middleware/types';

import { didsWithClaims, eventByIndexedArgs } from '../queries';
import { didsWithClaims, eventByIndexedArgs, proposalVotes } from '../queries';

describe('proposalVotes', () => {
test('should pass the variables to the grapqhl query', () => {
const variables = {
pipId: 10,
vote: false,
count: 50,
skip: 0,
orderBy: {
field: ProposalVotesOrderFields.Vote,
order: Order.Desc,
},
};

const result = proposalVotes(variables);

expect(result.query).toBeDefined();
expect(result.variables).toEqual(variables);
});
});

describe('didsWithClaims', () => {
test('should pass the variables to the grapqhl query', () => {
Expand Down
38 changes: 37 additions & 1 deletion src/middleware/queries.ts
@@ -1,8 +1,44 @@
import gql from 'graphql-tag';

import { QueryDidsWithClaimsArgs, QueryEventsByIndexedArgsArgs } from '~/middleware/types';
import {
QueryDidsWithClaimsArgs,
QueryEventsByIndexedArgsArgs,
QueryProposalVotesArgs,
} from '~/middleware/types';
import { GraphqlQuery } from '~/types/internal';

/**
* @hidden
*
* Get the current voters list for given pipId
*/
export function proposalVotes(
variables: QueryProposalVotesArgs
): GraphqlQuery<QueryProposalVotesArgs> {
const query = gql`
query ProposalVotesQuery(
$pipId: Int!
$vote: Boolean!
$count: Int
$skip: Int
$orderBy: ProposalVotesOrderByInput
) {
proposalVotes(pipId: $pipId, vote: $vote, count: $count, skip: $skip, orderBy: $orderBy) {
blockId
eventIdx
account
vote
weight
}
}
`;

return {
query,
variables,
};
}

/**
* @hidden
*
Expand Down

0 comments on commit 3054fe4

Please sign in to comment.