decode.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import { SubstrateEvent } from '../../generated/indexer'
  2. import {
  3. IPropertyIdWithName,
  4. IClassEntity,
  5. IProperty,
  6. IBatchOperation,
  7. ICreateEntityOperation,
  8. IEntity,
  9. IReference,
  10. } from '../types'
  11. import Debug from 'debug'
  12. import { ParametrizedClassPropertyValue, UpdatePropertyValuesOperation } from '@joystream/types/content-directory'
  13. import { createType } from '@joystream/types'
  14. const debug = Debug('mappings:cd:decode')
  15. function stringIfyEntityId(event: SubstrateEvent): string {
  16. const { 1: entityId } = event.params
  17. return entityId.value as string
  18. }
  19. function setProperties<T>({ extrinsic, blockNumber }: SubstrateEvent, propNamesWithId: IPropertyIdWithName): T {
  20. if (extrinsic === undefined) throw Error('Undefined extrinsic')
  21. const { 3: newPropertyValues } = extrinsic!.args
  22. const properties: { [key: string]: any; reference?: IReference } = {}
  23. for (const [k, v] of Object.entries(newPropertyValues.value)) {
  24. const propertyName = propNamesWithId[k]
  25. const singlePropVal = createType('InputPropertyValue', v as any).asType('Single')
  26. properties[propertyName] = singlePropVal.isOfType('Reference')
  27. ? { entityId: singlePropVal.asType('Reference').toJSON(), existing: true }
  28. : singlePropVal.value.toJSON()
  29. }
  30. properties.version = blockNumber
  31. debug(`Entity properties: ${JSON.stringify(properties)}`)
  32. return properties as T
  33. }
  34. function getClassEntity(event: SubstrateEvent): IClassEntity {
  35. const { 0: classId } = event.extrinsic!.args
  36. const { 1: entityId } = event.params
  37. return {
  38. entityId: (entityId.value as unknown) as number,
  39. classId: (classId.value as unknown) as number,
  40. }
  41. }
  42. /**
  43. * When entity is creation through `transaction` extrinsic we use this function to parse
  44. * entity properties it looks quite similar to `setProperties` function
  45. * @param properties
  46. * @param propertyNamesWithId
  47. */
  48. function setEntityPropertyValues<T>(properties: IProperty[], propertyNamesWithId: IPropertyIdWithName): T {
  49. const entityProperties: { [key: string]: any; reference?: IReference } = {}
  50. for (const [propId, propName] of Object.entries(propertyNamesWithId)) {
  51. // get the property value by id
  52. const p = properties.find((p) => p.id === propId)
  53. if (!p) continue
  54. entityProperties[propName] = p.reference ? p.reference : p.value
  55. }
  56. // debug(`Entity properties ${JSON.stringify(entityProperties)}`)
  57. return entityProperties as T
  58. }
  59. // Decode entity property values
  60. function getEntityProperties(propertyValues: ParametrizedClassPropertyValue[]): IProperty[] {
  61. const properties: IProperty[] = []
  62. const entityPropertyValues = createType('Vec<ParametrizedClassPropertyValue>', propertyValues)
  63. entityPropertyValues.map((pv: ParametrizedClassPropertyValue) => {
  64. const v = createType('ParametrizedPropertyValue', pv.value)
  65. const propertyId = pv.in_class_index.toJSON()
  66. let reference
  67. let value
  68. if (v.isOfType('InputPropertyValue')) {
  69. const inputPropVal = v.asType('InputPropertyValue')
  70. value = inputPropVal.isOfType('Single')
  71. ? inputPropVal.asType('Single').value.toJSON()
  72. : inputPropVal.asType('Vector').value.toJSON()
  73. } else if (v.isOfType('InternalEntityJustAdded')) {
  74. value = v.asType('InternalEntityJustAdded').toJSON()
  75. reference = { entityId: value as number, existing: false }
  76. } else {
  77. // TODO: Add support for v.asType('InternalEntityVec')
  78. throw Error('InternalEntityVec property type is not supported yet!')
  79. }
  80. properties.push({ id: `${propertyId}`, value, reference })
  81. })
  82. return properties
  83. }
  84. function getOperations({ extrinsic }: SubstrateEvent): IBatchOperation {
  85. const operations = createType('Vec<OperationType>', extrinsic!.args[1].value as any)
  86. const updatePropertyValuesOperations: IEntity[] = []
  87. const addSchemaSupportToEntityOperations: IEntity[] = []
  88. const createEntityOperations: ICreateEntityOperation[] = []
  89. for (const operation of operations) {
  90. if (operation.isOfType('CreateEntity')) {
  91. const cep = operation.asType('CreateEntity')
  92. createEntityOperations.push({ classId: cep.class_id.toJSON() })
  93. } else if (operation.isOfType('AddSchemaSupportToEntity')) {
  94. const op = operation.asType('AddSchemaSupportToEntity')
  95. const pe = createType('ParameterizedEntity', op.entity_id)
  96. const entity: IEntity = {
  97. properties: getEntityProperties(op.parametrized_property_values),
  98. }
  99. if (pe.isOfType('InternalEntityJustAdded')) {
  100. entity.indexOf = pe.asType('InternalEntityJustAdded').toJSON()
  101. } else {
  102. entity.entityId = pe.asType('ExistingEntity').toJSON()
  103. }
  104. addSchemaSupportToEntityOperations.push(entity)
  105. } else {
  106. updatePropertyValuesOperations.push(makeEntity(operation.asType('UpdatePropertyValues')))
  107. }
  108. }
  109. return {
  110. updatePropertyValuesOperations,
  111. addSchemaSupportToEntityOperations,
  112. createEntityOperations,
  113. }
  114. }
  115. function makeEntity(upv: UpdatePropertyValuesOperation): IEntity {
  116. const entity: IEntity = {
  117. properties: getEntityProperties(upv.new_parametrized_property_values),
  118. }
  119. const pe = createType('ParameterizedEntity', upv.entity_id)
  120. if (pe.isOfType('InternalEntityJustAdded')) {
  121. entity.indexOf = pe.asType('InternalEntityJustAdded').toJSON()
  122. } else {
  123. entity.entityId = pe.asType('ExistingEntity').toJSON()
  124. }
  125. return entity
  126. }
  127. export const decode = {
  128. stringIfyEntityId,
  129. getClassEntity,
  130. setEntityPropertyValues,
  131. getEntityProperties,
  132. getOperations,
  133. setProperties,
  134. }