transaction.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import Debug from 'debug'
  2. import { DB, SubstrateEvent } from '../../generated/indexer'
  3. import { decode } from './decode'
  4. import {
  5. ClassEntityMap,
  6. ICategory,
  7. IChannel,
  8. ICreateEntityOperation,
  9. IDBBlockId,
  10. IEntity,
  11. IHttpMediaLocation,
  12. IJoystreamMediaLocation,
  13. IKnownLicense,
  14. ILanguage,
  15. IUserDefinedLicense,
  16. IVideo,
  17. IVideoMedia,
  18. IVideoMediaEncoding,
  19. IWhereCond,
  20. } from '../types'
  21. import {
  22. CategoryPropertyNamesWithId,
  23. channelPropertyNamesWithId,
  24. knownLicensePropertyNamesWIthId,
  25. userDefinedLicensePropertyNamesWithId,
  26. joystreamMediaLocationPropertyNamesWithId,
  27. httpMediaLocationPropertyNamesWithId,
  28. videoMediaPropertyNamesWithId,
  29. videoMediaEncodingPropertyNamesWithId,
  30. videoPropertyNamesWithId,
  31. languagePropertyNamesWIthId,
  32. ContentDirectoryKnownClasses,
  33. } from './content-dir-consts'
  34. import {
  35. createCategory,
  36. createChannel,
  37. createVideoMedia,
  38. createVideo,
  39. createUserDefinedLicense,
  40. createKnownLicense,
  41. createHttpMediaLocation,
  42. createJoystreamMediaLocation,
  43. createLanguage,
  44. createVideoMediaEncoding,
  45. getClassName,
  46. updateCategoryEntityPropertyValues,
  47. updateChannelEntityPropertyValues,
  48. updateVideoMediaEntityPropertyValues,
  49. updateVideoEntityPropertyValues,
  50. updateUserDefinedLicenseEntityPropertyValues,
  51. updateHttpMediaLocationEntityPropertyValues,
  52. updateJoystreamMediaLocationEntityPropertyValues,
  53. updateKnownLicenseEntityPropertyValues,
  54. updateLanguageEntityPropertyValues,
  55. updateVideoMediaEncodingEntityPropertyValues,
  56. batchCreateClassEntities,
  57. } from './entity-helper'
  58. const debug = Debug('mappings:content-directory')
  59. // eslint-disable-next-line @typescript-eslint/naming-convention
  60. export async function contentDirectory_TransactionCompleted(db: DB, event: SubstrateEvent): Promise<void> {
  61. debug(`TransactionCompleted event: ${JSON.stringify(event)}`)
  62. const { extrinsic, blockNumber: block } = event
  63. if (!extrinsic) {
  64. throw Error(`No extrinsic found for the event: ${event.id}`)
  65. }
  66. const { 1: operations } = extrinsic.args
  67. if (operations.name.toString() !== 'operations') {
  68. throw Error(`Could not found 'operations' in the extrinsic.args[1]`)
  69. }
  70. const {
  71. addSchemaSupportToEntityOperations,
  72. createEntityOperations,
  73. updatePropertyValuesOperations,
  74. } = decode.getOperations(event)
  75. // Create entities before adding schema support
  76. // We need this to know which entity belongs to which class(we will need to know to update/create
  77. // Channel, Video etc.). For example if there is
  78. // a property update operation there is no class id
  79. await batchCreateClassEntities(db, block, createEntityOperations)
  80. await batchUpdatePropertyValue(db, createEntityOperations, updatePropertyValuesOperations)
  81. await batchAddSchemaSupportToEntity(db, createEntityOperations, addSchemaSupportToEntityOperations, block)
  82. }
  83. /**
  84. *
  85. * @param db database connection
  86. * @param createEntityOperations: Entity creations with in the same transaction
  87. * @param entities List of entities that schema support is added for
  88. * @param block block number
  89. */
  90. async function batchAddSchemaSupportToEntity(
  91. db: DB,
  92. createEntityOperations: ICreateEntityOperation[],
  93. entities: IEntity[],
  94. block: number
  95. ) {
  96. const classEntityMap: ClassEntityMap = new Map<string, IEntity[]>()
  97. for (const entity of entities) {
  98. const className = await getClassName(db, entity, createEntityOperations)
  99. if (className !== undefined) {
  100. const es = classEntityMap.get(className)
  101. classEntityMap.set(className, es ? [...es, entity] : [entity])
  102. }
  103. }
  104. // This is a copy of classEntityMap, we will use it to keep track of items.
  105. // We will remove items from this list whenever we insert them into db
  106. const doneList: ClassEntityMap = new Map(classEntityMap.entries())
  107. for (const [className, entities] of classEntityMap) {
  108. for (const entity of entities) {
  109. const { entityId, indexOf, properties } = entity
  110. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  111. const id = entityId ? entityId.toString() : indexOf!.toString()
  112. const arg: IDBBlockId = { db, block, id }
  113. switch (className) {
  114. case ContentDirectoryKnownClasses.CATEGORY:
  115. await createCategory(arg, decode.setEntityPropertyValues<ICategory>(properties, CategoryPropertyNamesWithId))
  116. break
  117. case ContentDirectoryKnownClasses.CHANNEL:
  118. await createChannel(
  119. arg,
  120. doneList,
  121. decode.setEntityPropertyValues<IChannel>(properties, channelPropertyNamesWithId)
  122. )
  123. break
  124. case ContentDirectoryKnownClasses.KNOWNLICENSE:
  125. await createKnownLicense(
  126. arg,
  127. decode.setEntityPropertyValues<IKnownLicense>(properties, knownLicensePropertyNamesWIthId)
  128. )
  129. break
  130. case ContentDirectoryKnownClasses.USERDEFINEDLICENSE:
  131. await createUserDefinedLicense(
  132. arg,
  133. decode.setEntityPropertyValues<IUserDefinedLicense>(properties, userDefinedLicensePropertyNamesWithId)
  134. )
  135. break
  136. case ContentDirectoryKnownClasses.JOYSTREAMMEDIALOCATION:
  137. await createJoystreamMediaLocation(
  138. arg,
  139. decode.setEntityPropertyValues<IJoystreamMediaLocation>(
  140. properties,
  141. joystreamMediaLocationPropertyNamesWithId
  142. )
  143. )
  144. break
  145. case ContentDirectoryKnownClasses.HTTPMEDIALOCATION:
  146. await createHttpMediaLocation(
  147. arg,
  148. decode.setEntityPropertyValues<IHttpMediaLocation>(properties, httpMediaLocationPropertyNamesWithId)
  149. )
  150. break
  151. case ContentDirectoryKnownClasses.VIDEOMEDIA:
  152. await createVideoMedia(
  153. arg,
  154. doneList,
  155. decode.setEntityPropertyValues<IVideoMedia>(properties, videoMediaPropertyNamesWithId)
  156. )
  157. break
  158. case ContentDirectoryKnownClasses.VIDEO:
  159. await createVideo(arg, doneList, decode.setEntityPropertyValues<IVideo>(properties, videoPropertyNamesWithId))
  160. break
  161. case ContentDirectoryKnownClasses.LANGUAGE:
  162. await createLanguage(arg, decode.setEntityPropertyValues<ILanguage>(properties, languagePropertyNamesWIthId))
  163. break
  164. case ContentDirectoryKnownClasses.VIDEOMEDIAENCODING:
  165. await createVideoMediaEncoding(
  166. arg,
  167. decode.setEntityPropertyValues<IVideoMediaEncoding>(properties, videoMediaEncodingPropertyNamesWithId)
  168. )
  169. break
  170. default:
  171. console.log(`Unknown class name: ${className}`)
  172. break
  173. }
  174. }
  175. }
  176. }
  177. /**
  178. * Batch update operations for entity properties values update
  179. * @param db database connection
  180. * @param createEntityOperations Entity creations with in the same transaction
  181. * @param entities list of entities those properties values updated
  182. */
  183. async function batchUpdatePropertyValue(db: DB, createEntityOperations: ICreateEntityOperation[], entities: IEntity[]) {
  184. for (const entity of entities) {
  185. const { entityId, indexOf, properties } = entity
  186. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  187. const id = entityId ? entityId.toString() : indexOf!.toString()
  188. const where: IWhereCond = { where: { id } }
  189. const className = await getClassName(db, entity, createEntityOperations)
  190. if (className === undefined) {
  191. console.log(`Can not update entity properties values. Unknown class name`)
  192. return
  193. }
  194. switch (className) {
  195. case ContentDirectoryKnownClasses.CHANNEL:
  196. await updateChannelEntityPropertyValues(
  197. db,
  198. where,
  199. decode.setEntityPropertyValues<IChannel>(properties, CategoryPropertyNamesWithId)
  200. )
  201. break
  202. case ContentDirectoryKnownClasses.CATEGORY:
  203. await updateCategoryEntityPropertyValues(
  204. db,
  205. where,
  206. decode.setEntityPropertyValues<ICategory>(properties, CategoryPropertyNamesWithId)
  207. )
  208. break
  209. case ContentDirectoryKnownClasses.KNOWNLICENSE:
  210. await updateKnownLicenseEntityPropertyValues(
  211. db,
  212. where,
  213. decode.setEntityPropertyValues<IKnownLicense>(properties, knownLicensePropertyNamesWIthId)
  214. )
  215. break
  216. case ContentDirectoryKnownClasses.USERDEFINEDLICENSE:
  217. await updateUserDefinedLicenseEntityPropertyValues(
  218. db,
  219. where,
  220. decode.setEntityPropertyValues<IUserDefinedLicense>(properties, userDefinedLicensePropertyNamesWithId)
  221. )
  222. break
  223. case ContentDirectoryKnownClasses.JOYSTREAMMEDIALOCATION:
  224. await updateJoystreamMediaLocationEntityPropertyValues(
  225. db,
  226. where,
  227. decode.setEntityPropertyValues<IJoystreamMediaLocation>(properties, joystreamMediaLocationPropertyNamesWithId)
  228. )
  229. break
  230. case ContentDirectoryKnownClasses.HTTPMEDIALOCATION:
  231. await updateHttpMediaLocationEntityPropertyValues(
  232. db,
  233. where,
  234. decode.setEntityPropertyValues<IHttpMediaLocation>(properties, httpMediaLocationPropertyNamesWithId)
  235. )
  236. break
  237. case ContentDirectoryKnownClasses.VIDEOMEDIA:
  238. await updateVideoMediaEntityPropertyValues(
  239. db,
  240. where,
  241. decode.setEntityPropertyValues<IVideoMedia>(properties, videoPropertyNamesWithId)
  242. )
  243. break
  244. case ContentDirectoryKnownClasses.VIDEO:
  245. await updateVideoEntityPropertyValues(
  246. db,
  247. where,
  248. decode.setEntityPropertyValues<IVideo>(properties, videoPropertyNamesWithId)
  249. )
  250. break
  251. case ContentDirectoryKnownClasses.LANGUAGE:
  252. await updateLanguageEntityPropertyValues(
  253. db,
  254. where,
  255. decode.setEntityPropertyValues<ILanguage>(properties, languagePropertyNamesWIthId)
  256. )
  257. break
  258. case ContentDirectoryKnownClasses.VIDEOMEDIAENCODING:
  259. await updateVideoMediaEncodingEntityPropertyValues(
  260. db,
  261. where,
  262. decode.setEntityPropertyValues<IVideoMediaEncoding>(properties, videoMediaEncodingPropertyNamesWithId)
  263. )
  264. break
  265. default:
  266. console.log(`Unknown class name: ${className}`)
  267. break
  268. }
  269. }
  270. }