-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
QN mappings review & fixes #4856
Changes from 6 commits
c86c975
f5606b2
7d861ae
a9223dc
a814f5f
761d6b1
96e99b8
b3f01a3
810240d
0de7603
e6a69ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module.exports = { | ||
'no-throw': { | ||
meta: { | ||
type: 'problem', | ||
docs: { | ||
description: 'disallow the use of throw keyword', | ||
category: 'Possible Errors', | ||
recommended: true, | ||
}, | ||
schema: [], | ||
}, | ||
|
||
create: function (context) { | ||
return { | ||
ThrowStatement(node) { | ||
context.report({ | ||
node: node, | ||
message: "The use of 'throw' keyword is not allowed.", | ||
}) | ||
}, | ||
} | ||
}, | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,29 @@ | ||
import { DatabaseManager, SubstrateEvent, FindOneOptions } from '@joystream/hydra-common' | ||
import { Bytes, Option } from '@polkadot/types' | ||
import { Codec } from '@polkadot/types/types' | ||
import { | ||
DatabaseManager, | ||
FindOneOptions, | ||
FindOptionsOrderValue, | ||
FindOptionsWhere, | ||
SubstrateEvent, | ||
} from '@joystream/hydra-common' | ||
import { AnyMetadataClass, DecodedMetadataObject } from '@joystream/metadata-protobuf/types' | ||
import { metaToObject } from '@joystream/metadata-protobuf/utils' | ||
import { MemberId, WorkerId } from '@joystream/types/primitives' | ||
import { BaseModel } from '@joystream/warthog' | ||
import { Bytes, Option } from '@polkadot/types' | ||
import { PalletCommonWorkingGroupIterableEnumsWorkingGroup as WGType } from '@polkadot/types/lookup' | ||
import { Codec } from '@polkadot/types/types' | ||
import BN from 'bn.js' | ||
import { | ||
Worker, | ||
Event, | ||
Network, | ||
WorkingGroup as WGEntity, | ||
MetaprotocolTransactionStatusEvent, | ||
Membership, | ||
MetaprotocolTransactionErrored, | ||
MetaprotocolTransactionStatusEvent, | ||
MetaprotocolTransactionSuccessful, | ||
Membership, | ||
Network, | ||
WorkingGroup as WGEntity, | ||
Worker, | ||
} from 'query-node/dist/model' | ||
import { BaseModel } from '@joystream/warthog' | ||
import { metaToObject } from '@joystream/metadata-protobuf/utils' | ||
import { AnyMetadataClass, DecodedMetadataObject } from '@joystream/metadata-protobuf/types' | ||
import BN from 'bn.js' | ||
import { In } from 'typeorm' | ||
|
||
export const CURRENT_NETWORK = Network.OLYMPIA | ||
|
||
|
@@ -88,18 +95,20 @@ export function inconsistentState(extraInfo: string, data?: unknown): never { | |
// log error | ||
logger.error(errorMessage, data) | ||
|
||
// eslint-disable-next-line local-rules/no-throw | ||
throw errorMessage | ||
} | ||
|
||
/* | ||
Reports that insurmountable unexpected data has been encountered and throws an exception. | ||
*/ | ||
export function unexpectedData(extraInfo: string, data?: unknown): never { | ||
const errorMessage = 'Unexpected data: ' + extraInfo | ||
/** | ||
* Reports an unimplemented mapping/variant error for which a runtime implementation logic exists and is not filtered. | ||
*/ | ||
export function unimplementedError(extraInfo: string, data?: unknown): never { | ||
const errorMessage = 'unimplemented error: ' + extraInfo | ||
|
||
// log error | ||
logger.error(errorMessage, data) | ||
|
||
// eslint-disable-next-line local-rules/no-throw | ||
throw errorMessage | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in 810240d |
||
|
||
|
@@ -124,7 +133,7 @@ export function deserializeMetadata<T>( | |
const message = metadataType.decode(metadataBytes.toU8a(true)) | ||
Object.keys(message).forEach((key) => { | ||
if (key in message && typeof message[key] === 'string') { | ||
message[key] = perpareString(message[key]) | ||
message[key] = prepareString(message[key]) | ||
} | ||
}) | ||
return metaToObject(metadataType, message) | ||
|
@@ -145,7 +154,7 @@ export function bytesToString(b: Bytes): string { | |
) | ||
} | ||
|
||
export function perpareString(s: string): string { | ||
export function prepareString(s: string): string { | ||
// eslint-disable-next-line no-control-regex | ||
return s.replace(/\u0000/g, '') | ||
} | ||
|
@@ -211,55 +220,33 @@ export function getWorkingGroupModuleName(group: WGType): WorkingGroupModuleName | |
return 'operationsWorkingGroupGamma' | ||
} | ||
|
||
unexpectedData('Unsupported working group encountered:', group.type) | ||
unimplementedError('Unsupported working group encountered:', group.type) | ||
} | ||
|
||
export async function getWorkingGroupByName( | ||
export async function getWorkingGroupByNameOrFail( | ||
store: DatabaseManager, | ||
name: WorkingGroupModuleName, | ||
relations: string[] = [] | ||
relations: RelationsArr<WGEntity> = [] | ||
): Promise<WGEntity> { | ||
const group = await store.get(WGEntity, { where: { name }, relations }) | ||
if (!group) { | ||
return inconsistentState(`Working group ${name} not found!`) | ||
} | ||
return group | ||
return getOneByOrFail(store, WGEntity, { name }, relations) | ||
} | ||
|
||
export async function getMemberById( | ||
export async function getMembershipById( | ||
store: DatabaseManager, | ||
id: MemberId, | ||
relations: string[] = [] | ||
relations: RelationsArr<Membership> = [] | ||
): Promise<Membership> { | ||
const member = await store.get(Membership, { where: { id: id.toString() }, relations }) | ||
if (!member) { | ||
throw new Error(`Member(${id}) not found`) | ||
} | ||
return member | ||
} | ||
|
||
export async function getWorkingGroupLead(store: DatabaseManager, groupName: WorkingGroupModuleName) { | ||
const lead = await store.get(Worker, { where: { groupId: groupName, isLead: true, isActive: true } }) | ||
if (!lead) { | ||
return inconsistentState(`Couldn't find an active lead for ${groupName}`) | ||
} | ||
|
||
return lead | ||
return getByIdOrFail(store, Membership, id.toString(), relations) | ||
} | ||
|
||
export async function getWorker( | ||
export async function getWorkerOrFail( | ||
store: DatabaseManager, | ||
groupName: WorkingGroupModuleName, | ||
runtimeId: WorkerId | number, | ||
relations: string[] = [] | ||
relations: RelationsArr<Worker> = [] | ||
): Promise<Worker> { | ||
const workerDbId = `${groupName}-${runtimeId}` | ||
const worker = await store.get(Worker, { where: { id: workerDbId }, relations }) | ||
if (!worker) { | ||
return inconsistentState(`Expected worker not found by id ${workerDbId}`) | ||
} | ||
|
||
return worker | ||
return getByIdOrFail(store, Worker, workerDbId, relations) | ||
} | ||
|
||
type EntityClass<T extends BaseModel> = { | ||
|
@@ -277,15 +264,93 @@ export async function getById<T extends BaseModel>( | |
entityClass: EntityClass<T>, | ||
id: string, | ||
relations?: RelationsArr<T> | ||
): Promise<T | undefined> { | ||
return store.get(entityClass, { where: { id }, relations } as FindOneOptions<T>) | ||
} | ||
|
||
export async function getByIdOrFail<T extends BaseModel>( | ||
store: DatabaseManager, | ||
entityClass: EntityClass<T>, | ||
id: string, | ||
relations?: RelationsArr<T>, | ||
errMessage?: string | ||
): Promise<T> { | ||
const result = await getById<T>(store, entityClass, id, relations) | ||
if (!result) { | ||
// eslint-disable-next-line local-rules/no-throw | ||
throw new Error(`Expected "${entityClass.name}" not found by ID: ${id} ${errMessage ? `- ${errMessage}` : ''}`) | ||
} | ||
|
||
return result | ||
} | ||
|
||
export async function getOneBy<T extends BaseModel>( | ||
store: DatabaseManager, | ||
entityClass: EntityClass<T>, | ||
where?: FindOptionsWhere<T>, | ||
relations?: RelationsArr<T>, | ||
order?: Partial<{ [K in keyof T]: FindOptionsOrderValue }> | ||
): Promise<T | undefined> { | ||
return store.get(entityClass, { where, relations, order } as FindOneOptions<T>) | ||
} | ||
|
||
/** | ||
* Retrieves a entity by any field(s) or throws an error if not found | ||
*/ | ||
export async function getOneByOrFail<T extends BaseModel>( | ||
store: DatabaseManager, | ||
entityClass: EntityClass<T>, | ||
where?: FindOptionsWhere<T>, | ||
relations?: RelationsArr<T>, | ||
order?: Partial<{ [K in keyof T]: FindOptionsOrderValue }>, | ||
errMessage?: string | ||
): Promise<T> { | ||
const result = await store.get(entityClass, { where: { id }, relations } as FindOneOptions<T>) | ||
const result = await getOneBy(store, entityClass, where, relations, order) | ||
if (!result) { | ||
throw new Error(`Expected ${entityClass.name} not found by ID: ${id}`) | ||
// eslint-disable-next-line local-rules/no-throw | ||
throw new Error( | ||
`Expected "${entityClass.name}" not found by filter: ${JSON.stringify({ | ||
where, | ||
relations, | ||
order, | ||
})} ${errMessage ? `- ${errMessage}` : ''}` | ||
) | ||
} | ||
|
||
return result | ||
} | ||
|
||
export async function getManyBy<T extends BaseModel>( | ||
store: DatabaseManager, | ||
entityClass: EntityClass<T>, | ||
entityIds: string[], | ||
where?: FindOptionsWhere<T>, | ||
relations?: RelationsArr<T> | ||
): Promise<T[]> { | ||
return store.getMany(entityClass, { where: { id: In(entityIds), ...where }, relations } as FindOneOptions<T>) | ||
} | ||
|
||
export async function getManyByOrFail<T extends BaseModel>( | ||
store: DatabaseManager, | ||
entityClass: EntityClass<T>, | ||
entityIds: string[], | ||
where?: FindOptionsWhere<T>, | ||
relations?: RelationsArr<T>, | ||
errMessage?: string | ||
): Promise<T[]> { | ||
const entities = await getManyBy(store, entityClass, entityIds, where, relations) | ||
const loadedEntityIds = entities.map((item) => item.id) | ||
if (loadedEntityIds.length !== entityIds.length) { | ||
const missingIds = entityIds.filter((item) => !loadedEntityIds.includes(item)) | ||
|
||
// eslint-disable-next-line local-rules/no-throw | ||
throw new Error( | ||
`"${entityClass.name}" missing records for following IDs: ${missingIds} ${errMessage ? `- ${errMessage}` : ''}` | ||
) | ||
} | ||
return entities | ||
} | ||
|
||
export function deterministicEntityId(createdInEvent: SubstrateEvent, additionalIdentifier?: string | number): string { | ||
return ( | ||
`${createdInEvent.blockNumber}-${createdInEvent.indexInBlock}` + | ||
|
@@ -332,10 +397,10 @@ export async function saveMetaprotocolTransactionSuccessful( | |
export async function saveMetaprotocolTransactionErrored( | ||
store: DatabaseManager, | ||
event: SubstrateEvent, | ||
message: string | ||
error: MetaprotocolTxError | ||
): Promise<void> { | ||
const status = new MetaprotocolTransactionErrored() | ||
status.message = message | ||
status.message = error | ||
|
||
const metaprotocolTransaction = new MetaprotocolTransactionStatusEvent({ | ||
...genericEventFields(event), | ||
|
@@ -344,3 +409,30 @@ export async function saveMetaprotocolTransactionErrored( | |
|
||
await store.save(metaprotocolTransaction) | ||
} | ||
|
||
export enum MetaprotocolTxError { | ||
InvalidMetadata = 'InvalidMetadata', | ||
|
||
// App errors | ||
AppAlreadyExists = 'AppAlreadyExists', | ||
AppNotFound = 'AppNotFound', | ||
InvalidAppOwnerMember = 'InvalidAppOwnerMember', | ||
|
||
// Video errors | ||
VideoNotFound = 'VideoNotFound', | ||
VideoNotFoundInChannel = 'VideoNotFoundInChannel', | ||
VideoReactionsDisabled = 'VideoReactionsDisabled', | ||
|
||
// Comment errors | ||
CommentSectionDisabled = 'CommentSectionDisabled', | ||
CommentNotFound = 'CommentNotFound', | ||
ParentCommentNotFound = 'ParentCommentNotFound', | ||
InvalidCommentAuthor = 'InvalidCommentAuthor', | ||
|
||
// Membership error | ||
MemberNotFound = 'MemberNotFound', | ||
MemberBannedFromChannel = 'MemberBannedFromChannel', | ||
|
||
// Channel errors | ||
InvalidChannelRewardAccount = 'InvalidChannelRewardAccount', | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this package seems to require native build on mac/arm64 so I had to add
node-gyp
as a dev dependency to successfully build docker image of query-node.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in b3f01a3