entity-helper.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. import { DB, SubstrateEvent } from '../../generated/indexer'
  2. import { Channel } from '../../generated/graphql-server/src/modules/channel/channel.model'
  3. import { Category } from '../../generated/graphql-server/src/modules/category/category.model'
  4. import { KnownLicense } from '../../generated/graphql-server/src/modules/known-license/known-license.model'
  5. import { UserDefinedLicense } from '../../generated/graphql-server/src/modules/user-defined-license/user-defined-license.model'
  6. import { JoystreamMediaLocation } from '../../generated/graphql-server/src/modules/joystream-media-location/joystream-media-location.model'
  7. import { HttpMediaLocation } from '../../generated/graphql-server/src/modules/http-media-location/http-media-location.model'
  8. import { VideoMedia } from '../../generated/graphql-server/src/modules/video-media/video-media.model'
  9. import { Video } from '../../generated/graphql-server/src/modules/video/video.model'
  10. import { Block, Network } from '../../generated/graphql-server/src/modules/block/block.model'
  11. import { Language } from '../../generated/graphql-server/src/modules/language/language.model'
  12. import { VideoMediaEncoding } from '../../generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.model'
  13. import { ClassEntity } from '../../generated/graphql-server/src/modules/class-entity/class-entity.model'
  14. import { decode } from './decode'
  15. import {
  16. CategoryPropertyNamesWithId,
  17. channelPropertyNamesWithId,
  18. httpMediaLocationPropertyNamesWithId,
  19. joystreamMediaLocationPropertyNamesWithId,
  20. knownLicensePropertyNamesWIthId,
  21. languagePropertyNamesWIthId,
  22. userDefinedLicensePropertyNamesWithId,
  23. videoMediaEncodingPropertyNamesWithId,
  24. videoPropertyNamesWithId,
  25. contentDirectoryClassNamesWithId,
  26. ContentDirectoryKnownClasses,
  27. } from './content-dir-consts'
  28. import {
  29. ICategory,
  30. IChannel,
  31. ICreateEntityOperation,
  32. IDBBlockId,
  33. IEntity,
  34. IHttpMediaLocation,
  35. IJoystreamMediaLocation,
  36. IKnownLicense,
  37. ILanguage,
  38. IUserDefinedLicense,
  39. IVideo,
  40. IVideoMedia,
  41. IVideoMediaEncoding,
  42. IWhereCond,
  43. } from '../types'
  44. async function createBlockOrGetFromDatabase(db: DB, blockNumber: number): Promise<Block> {
  45. let b = await db.get(Block, { where: { block: blockNumber } })
  46. if (b === undefined) {
  47. // TODO: get timestamp from the event or extrinsic
  48. b = new Block({ block: blockNumber, nework: Network.BABYLON, timestamp: 123 })
  49. await db.save<Block>(b)
  50. }
  51. return b
  52. }
  53. async function createChannel({ db, block, id }: IDBBlockId, p: IChannel): Promise<void> {
  54. // const { properties: p } = decode.channelEntity(event);
  55. const channel = new Channel()
  56. channel.version = block
  57. channel.id = id
  58. channel.title = p.title
  59. channel.description = p.description
  60. channel.isCurated = p.isCurated || false
  61. channel.isPublic = p.isPublic
  62. channel.coverPhotoUrl = p.coverPhotoURL
  63. channel.avatarPhotoUrl = p.avatarPhotoURL
  64. channel.languageId = p.language
  65. channel.happenedIn = await createBlockOrGetFromDatabase(db, block)
  66. await db.save(channel)
  67. }
  68. async function createCategory({ db, block, id }: IDBBlockId, p: ICategory): Promise<void> {
  69. // const p = decode.categoryEntity(event);
  70. const category = new Category()
  71. category.id = id
  72. category.name = p.name
  73. category.description = p.description
  74. category.version = block
  75. category.happenedIn = await createBlockOrGetFromDatabase(db, block)
  76. await db.save(category)
  77. }
  78. async function createKnownLicense({ db, block, id }: IDBBlockId, p: IKnownLicense): Promise<void> {
  79. const knownLicence = new KnownLicense()
  80. knownLicence.id = id
  81. knownLicence.code = p.code
  82. knownLicence.name = p.name
  83. knownLicence.description = p.description
  84. knownLicence.url = p.url
  85. knownLicence.version = block
  86. knownLicence.happenedIn = await createBlockOrGetFromDatabase(db, block)
  87. await db.save(knownLicence)
  88. }
  89. async function createUserDefinedLicense({ db, block, id }: IDBBlockId, p: IUserDefinedLicense): Promise<void> {
  90. const userDefinedLicense = new UserDefinedLicense()
  91. userDefinedLicense.id = id
  92. userDefinedLicense.content = p.content
  93. userDefinedLicense.version = block
  94. userDefinedLicense.happenedIn = await createBlockOrGetFromDatabase(db, block)
  95. await db.save(userDefinedLicense)
  96. }
  97. async function createJoystreamMediaLocation({ db, block, id }: IDBBlockId, p: IJoystreamMediaLocation): Promise<void> {
  98. const joyMediaLoc = new JoystreamMediaLocation()
  99. joyMediaLoc.id = id
  100. joyMediaLoc.dataObjectId = p.dataObjectId
  101. joyMediaLoc.version = block
  102. joyMediaLoc.happenedIn = await createBlockOrGetFromDatabase(db, block)
  103. await db.save(joyMediaLoc)
  104. }
  105. async function createHttpMediaLocation({ db, block, id }: IDBBlockId, p: IHttpMediaLocation): Promise<void> {
  106. const httpMediaLoc = new HttpMediaLocation()
  107. httpMediaLoc.id = id
  108. httpMediaLoc.url = p.url
  109. httpMediaLoc.port = p.port
  110. httpMediaLoc.version = block
  111. httpMediaLoc.happenedIn = await createBlockOrGetFromDatabase(db, block)
  112. await db.save(httpMediaLoc)
  113. }
  114. async function createVideoMedia({ db, block, id }: IDBBlockId, p: IVideoMedia): Promise<void> {
  115. const videoMedia = new VideoMedia()
  116. videoMedia.id = id
  117. videoMedia.encodingId = p.encoding
  118. videoMedia.locationId = p.location
  119. videoMedia.pixelHeight = p.pixelHeight
  120. videoMedia.pixelWidth = p.pixelWidth
  121. videoMedia.size = p.size
  122. videoMedia.version = block
  123. videoMedia.happenedIn = await createBlockOrGetFromDatabase(db, block)
  124. await db.save(videoMedia)
  125. }
  126. async function createVideo({ db, block, id }: IDBBlockId, p: IVideo): Promise<void> {
  127. const video = new Video()
  128. video.id = id
  129. video.title = p.title
  130. video.description = p.description
  131. video.categoryId = p.category
  132. video.channelId = p.channel
  133. video.duration = p.duration
  134. video.hasMarketing = p.hasMarketing
  135. // TODO: needs to be handled correctly, from runtime CurationStatus is coming
  136. video.isCurated = p.isCurated || true
  137. video.isExplicit = p.isExplicit
  138. video.isPublic = p.isPublic
  139. video.languageId = p.language
  140. video.licenseId = p.license
  141. video.videoMediaId = p.media
  142. video.publishedBeforeJoystream = p.publishedBeforeJoystream
  143. video.skippableIntroDuration = p.skippableIntroDuration
  144. video.thumbnailUrl = p.thumbnailURL
  145. video.version = block
  146. video.happenedIn = await createBlockOrGetFromDatabase(db, block)
  147. await db.save<Video>(video)
  148. }
  149. async function createLanguage({ db, block, id }: IDBBlockId, p: ILanguage): Promise<void> {
  150. const language = new Language()
  151. language.id = id
  152. language.name = p.name
  153. language.code = p.code
  154. language.version = block
  155. language.happenedIn = await createBlockOrGetFromDatabase(db, block)
  156. await db.save<Language>(language)
  157. }
  158. async function createVideoMediaEncoding({ db, block, id }: IDBBlockId, p: IVideoMediaEncoding): Promise<void> {
  159. const encoding = new VideoMediaEncoding()
  160. encoding.id = id
  161. encoding.name = p.name
  162. encoding.version = block
  163. // happenedIn is not defined in the graphql schema!
  164. // encoding.happenedIn = await createBlockOrGetFromDatabase(db, block)
  165. await db.save<VideoMediaEncoding>(encoding)
  166. }
  167. async function batchCreateClassEntities(db: DB, block: number, operations: ICreateEntityOperation[]): Promise<void> {
  168. // Create entities before adding schema support
  169. operations.map(async ({ classId }, index) => {
  170. const c = new ClassEntity()
  171. c.id = index.toString()
  172. c.classId = classId
  173. c.version = block
  174. c.happenedIn = await createBlockOrGetFromDatabase(db, block)
  175. await db.save<ClassEntity>(c)
  176. })
  177. }
  178. async function getClassName(
  179. db: DB,
  180. entity: IEntity,
  181. createEntityOperations: ICreateEntityOperation[]
  182. ): Promise<string | undefined> {
  183. const { entityId, indexOf } = entity
  184. if (entityId === undefined && indexOf === undefined) {
  185. throw Error(`Can not determine class of the entity`)
  186. }
  187. let classId: number | undefined
  188. // Is newly created entity in the same transaction
  189. if (indexOf !== undefined) {
  190. classId = createEntityOperations[indexOf].classId
  191. } else {
  192. const ce = await db.get(ClassEntity, { where: { id: entityId } })
  193. if (ce === undefined) console.log(`Class not found for the entity: ${entityId}`)
  194. classId = ce ? ce.classId : undefined
  195. }
  196. const c = contentDirectoryClassNamesWithId.find((c) => c.classId === classId)
  197. // TODO: stop execution, class should be created before entity creation
  198. if (c === undefined) console.log(`Not recognized class id: ${classId}`)
  199. return c ? c.name : undefined
  200. }
  201. async function removeChannel(db: DB, where: IWhereCond): Promise<void> {
  202. const record = await db.get(Channel, where)
  203. if (record === undefined) throw Error(`Channel not found`)
  204. await db.remove<Channel>(record)
  205. }
  206. async function removeCategory(db: DB, where: IWhereCond): Promise<void> {
  207. const record = await db.get(Category, where)
  208. if (record === undefined) throw Error(`Category not found`)
  209. await db.remove<Category>(record)
  210. }
  211. async function removeVideoMedia(db: DB, where: IWhereCond): Promise<void> {
  212. const record = await db.get(VideoMedia, where)
  213. if (record === undefined) throw Error(`VideoMedia not found`)
  214. await db.remove<VideoMedia>(record)
  215. }
  216. async function removeVideo(db: DB, where: IWhereCond): Promise<void> {
  217. const record = await db.get(Video, where)
  218. if (record === undefined) throw Error(`Video not found`)
  219. await db.remove<Video>(record)
  220. }
  221. async function removeUserDefinedLicense(db: DB, where: IWhereCond): Promise<void> {
  222. const record = await db.get(UserDefinedLicense, where)
  223. if (record === undefined) throw Error(`UserDefinedLicense not found`)
  224. await db.remove<UserDefinedLicense>(record)
  225. }
  226. async function removeKnownLicense(db: DB, where: IWhereCond): Promise<void> {
  227. const record = await db.get(KnownLicense, where)
  228. if (record === undefined) throw Error(`KnownLicense not found`)
  229. await db.remove<KnownLicense>(record)
  230. }
  231. async function removeHttpMediaLocation(db: DB, where: IWhereCond): Promise<void> {
  232. const record = await db.get(HttpMediaLocation, where)
  233. if (record === undefined) throw Error(`HttpMediaLocation not found`)
  234. await db.remove<HttpMediaLocation>(record)
  235. }
  236. async function removeJoystreamMediaLocation(db: DB, where: IWhereCond): Promise<void> {
  237. const record = await db.get(JoystreamMediaLocation, where)
  238. if (record === undefined) throw Error(`JoystreamMediaLocation not found`)
  239. await db.remove<JoystreamMediaLocation>(record)
  240. }
  241. async function removeLanguage(db: DB, where: IWhereCond): Promise<void> {
  242. const record = await db.get(Language, where)
  243. if (record === undefined) throw Error(`Language not found`)
  244. await db.remove<Language>(record)
  245. }
  246. async function removeVideoMediaEncoding(db: DB, where: IWhereCond): Promise<void> {
  247. const record = await db.get(VideoMediaEncoding, where)
  248. if (record === undefined) throw Error(`Language not found`)
  249. await db.remove<VideoMediaEncoding>(record)
  250. }
  251. // ========Entity property value updates========
  252. async function updateCategoryEntityPropertyValues(db: DB, where: IWhereCond, props: ICategory): Promise<void> {
  253. const record = await db.get(Category, where)
  254. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  255. Object.assign(record, props)
  256. await db.save<Category>(record)
  257. }
  258. async function updateChannelEntityPropertyValues(db: DB, where: IWhereCond, props: IChannel): Promise<void> {
  259. const record = await db.get(Channel, where)
  260. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  261. Object.assign(record, props)
  262. await db.save<Channel>(record)
  263. }
  264. async function updateVideoMediaEntityPropertyValues(db: DB, where: IWhereCond, props: IVideoMedia): Promise<void> {
  265. const record = await db.get(VideoMedia, where)
  266. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  267. Object.assign(record, props)
  268. await db.save<VideoMedia>(record)
  269. }
  270. async function updateVideoEntityPropertyValues(db: DB, where: IWhereCond, props: IVideo): Promise<void> {
  271. const record = await db.get(Video, where)
  272. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  273. Object.assign(record, props)
  274. await db.save<Video>(record)
  275. }
  276. async function updateUserDefinedLicenseEntityPropertyValues(
  277. db: DB,
  278. where: IWhereCond,
  279. props: IUserDefinedLicense
  280. ): Promise<void> {
  281. const record = await db.get(UserDefinedLicense, where)
  282. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  283. Object.assign(record, props)
  284. await db.save<UserDefinedLicense>(record)
  285. }
  286. async function updateKnownLicenseEntityPropertyValues(db: DB, where: IWhereCond, props: IKnownLicense): Promise<void> {
  287. const record = await db.get(KnownLicense, where)
  288. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  289. Object.assign(record, props)
  290. await db.save<KnownLicense>(record)
  291. }
  292. async function updateHttpMediaLocationEntityPropertyValues(
  293. db: DB,
  294. where: IWhereCond,
  295. props: IHttpMediaLocation
  296. ): Promise<void> {
  297. const record = await db.get(HttpMediaLocation, where)
  298. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  299. Object.assign(record, props)
  300. await db.save<HttpMediaLocation>(record)
  301. }
  302. async function updateJoystreamMediaLocationEntityPropertyValues(
  303. db: DB,
  304. where: IWhereCond,
  305. props: IJoystreamMediaLocation
  306. ): Promise<void> {
  307. const record = await db.get(JoystreamMediaLocation, where)
  308. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  309. Object.assign(record, props)
  310. await db.save<JoystreamMediaLocation>(record)
  311. }
  312. async function updateLanguageEntityPropertyValues(db: DB, where: IWhereCond, props: ILanguage): Promise<void> {
  313. const record = await db.get(Language, where)
  314. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  315. Object.assign(record, props)
  316. await db.save<Language>(record)
  317. }
  318. async function updateVideoMediaEncodingEntityPropertyValues(
  319. db: DB,
  320. where: IWhereCond,
  321. props: IVideoMediaEncoding
  322. ): Promise<void> {
  323. const record = await db.get(VideoMediaEncoding, where)
  324. if (record === undefined) throw Error(`Entity not found: ${where.where.id}`)
  325. Object.assign(record, props)
  326. await db.save<VideoMediaEncoding>(record)
  327. }
  328. async function updateEntityPropertyValues(
  329. db: DB,
  330. event: SubstrateEvent,
  331. where: IWhereCond,
  332. className: string
  333. ): Promise<void> {
  334. switch (className) {
  335. case ContentDirectoryKnownClasses.CHANNEL:
  336. updateChannelEntityPropertyValues(db, where, decode.setProperties<IChannel>(event, channelPropertyNamesWithId))
  337. break
  338. case ContentDirectoryKnownClasses.CATEGORY:
  339. await updateCategoryEntityPropertyValues(
  340. db,
  341. where,
  342. decode.setProperties<ICategory>(event, CategoryPropertyNamesWithId)
  343. )
  344. break
  345. case ContentDirectoryKnownClasses.KNOWNLICENSE:
  346. await updateKnownLicenseEntityPropertyValues(
  347. db,
  348. where,
  349. decode.setProperties<IKnownLicense>(event, knownLicensePropertyNamesWIthId)
  350. )
  351. break
  352. case ContentDirectoryKnownClasses.USERDEFINEDLICENSE:
  353. await updateUserDefinedLicenseEntityPropertyValues(
  354. db,
  355. where,
  356. decode.setProperties<IUserDefinedLicense>(event, userDefinedLicensePropertyNamesWithId)
  357. )
  358. break
  359. case ContentDirectoryKnownClasses.JOYSTREAMMEDIALOCATION:
  360. await updateJoystreamMediaLocationEntityPropertyValues(
  361. db,
  362. where,
  363. decode.setProperties<IJoystreamMediaLocation>(event, joystreamMediaLocationPropertyNamesWithId)
  364. )
  365. break
  366. case ContentDirectoryKnownClasses.HTTPMEDIALOCATION:
  367. await updateHttpMediaLocationEntityPropertyValues(
  368. db,
  369. where,
  370. decode.setProperties<IHttpMediaLocation>(event, httpMediaLocationPropertyNamesWithId)
  371. )
  372. break
  373. case ContentDirectoryKnownClasses.VIDEOMEDIA:
  374. await updateVideoMediaEntityPropertyValues(
  375. db,
  376. where,
  377. decode.setProperties<IVideoMedia>(event, videoPropertyNamesWithId)
  378. )
  379. break
  380. case ContentDirectoryKnownClasses.VIDEO:
  381. await updateVideoEntityPropertyValues(db, where, decode.setProperties<IVideo>(event, videoPropertyNamesWithId))
  382. break
  383. case ContentDirectoryKnownClasses.LANGUAGE:
  384. await updateLanguageEntityPropertyValues(
  385. db,
  386. where,
  387. decode.setProperties<ILanguage>(event, languagePropertyNamesWIthId)
  388. )
  389. break
  390. case ContentDirectoryKnownClasses.VIDEOMEDIAENCODING:
  391. await updateVideoMediaEncodingEntityPropertyValues(
  392. db,
  393. where,
  394. decode.setProperties<IVideoMediaEncoding>(event, videoMediaEncodingPropertyNamesWithId)
  395. )
  396. break
  397. default:
  398. throw new Error(`Unknown class name: ${className}`)
  399. }
  400. }
  401. export {
  402. createCategory,
  403. createChannel,
  404. createVideoMedia,
  405. createVideo,
  406. createUserDefinedLicense,
  407. createKnownLicense,
  408. createHttpMediaLocation,
  409. createJoystreamMediaLocation,
  410. createLanguage,
  411. createVideoMediaEncoding,
  412. removeCategory,
  413. removeChannel,
  414. removeVideoMedia,
  415. removeVideo,
  416. removeUserDefinedLicense,
  417. removeKnownLicense,
  418. removeHttpMediaLocation,
  419. removeJoystreamMediaLocation,
  420. removeLanguage,
  421. removeVideoMediaEncoding,
  422. createBlockOrGetFromDatabase,
  423. batchCreateClassEntities,
  424. getClassName,
  425. updateCategoryEntityPropertyValues,
  426. updateChannelEntityPropertyValues,
  427. updateVideoMediaEntityPropertyValues,
  428. updateVideoEntityPropertyValues,
  429. updateUserDefinedLicenseEntityPropertyValues,
  430. updateHttpMediaLocationEntityPropertyValues,
  431. updateJoystreamMediaLocationEntityPropertyValues,
  432. updateKnownLicenseEntityPropertyValues,
  433. updateLanguageEntityPropertyValues,
  434. updateVideoMediaEncodingEntityPropertyValues,
  435. updateEntityPropertyValues,
  436. }