create.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. import { DB } 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 { KnownLicenseEntity } from '../../../generated/graphql-server/src/modules/known-license-entity/known-license-entity.model'
  5. import { UserDefinedLicenseEntity } from '../../../generated/graphql-server/src/modules/user-defined-license-entity/user-defined-license-entity.model'
  6. import { JoystreamMediaLocationEntity } from '../../../generated/graphql-server/src/modules/joystream-media-location-entity/joystream-media-location-entity.model'
  7. import { HttpMediaLocationEntity } from '../../../generated/graphql-server/src/modules/http-media-location-entity/http-media-location-entity.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 { LicenseEntity } from '../../../generated/graphql-server/src/modules/license-entity/license-entity.model'
  15. import { MediaLocationEntity } from '../../../generated/graphql-server/src/modules/media-location-entity/media-location-entity.model'
  16. import { contentDirectoryClassNamesWithId } from '../content-dir-consts'
  17. import {
  18. ClassEntityMap,
  19. ICategory,
  20. IChannel,
  21. ICreateEntityOperation,
  22. IDBBlockId,
  23. IEntity,
  24. IHttpMediaLocation,
  25. IJoystreamMediaLocation,
  26. IKnownLicense,
  27. ILanguage,
  28. ILicense,
  29. IMediaLocation,
  30. IUserDefinedLicense,
  31. IVideo,
  32. IVideoMedia,
  33. IVideoMediaEncoding,
  34. } from '../../types'
  35. import { getOrCreate } from '../get-or-create'
  36. import BN from 'bn.js'
  37. import {
  38. HttpMediaLocation,
  39. JoystreamMediaLocation,
  40. KnownLicense,
  41. UserDefinedLicense,
  42. } from '../../../generated/graphql-server/src/modules/variants/variants.model'
  43. async function createBlockOrGetFromDatabase(db: DB, blockNumber: number): Promise<Block> {
  44. let b = await db.get(Block, { where: { block: blockNumber } })
  45. if (b === undefined) {
  46. // TODO: get timestamp from the event or extrinsic
  47. b = new Block({ block: blockNumber, network: Network.BABYLON, timestamp: new BN(Date.now()) })
  48. await db.save<Block>(b)
  49. }
  50. return b
  51. }
  52. async function createChannel(
  53. { db, block, id }: IDBBlockId,
  54. classEntityMap: ClassEntityMap,
  55. p: IChannel,
  56. nextEntityIdBeforeTransaction: number
  57. ): Promise<Channel> {
  58. const record = await db.get(Channel, { where: { id } })
  59. if (record) return record
  60. const channel = new Channel()
  61. channel.version = block
  62. channel.id = id
  63. channel.handle = p.handle
  64. channel.description = p.description
  65. channel.isCurated = p.isCurated || false
  66. channel.isPublic = p.isPublic
  67. channel.coverPhotoUrl = p.coverPhotoUrl
  68. channel.avatarPhotoUrl = p.avatarPhotoUrl
  69. channel.happenedIn = await createBlockOrGetFromDatabase(db, block)
  70. const { language } = p
  71. if (language) {
  72. channel.language = await getOrCreate.language(
  73. { db, block, id },
  74. classEntityMap,
  75. language,
  76. nextEntityIdBeforeTransaction
  77. )
  78. }
  79. await db.save(channel)
  80. return channel
  81. }
  82. async function createCategory({ db, block, id }: IDBBlockId, p: ICategory): Promise<Category> {
  83. const record = await db.get(Category, { where: { id } })
  84. if (record) return record
  85. const category = new Category()
  86. category.id = id
  87. category.name = p.name
  88. category.description = p.description
  89. category.version = block
  90. category.happenedIn = await createBlockOrGetFromDatabase(db, block)
  91. await db.save(category)
  92. return category
  93. }
  94. async function createKnownLicense({ db, block, id }: IDBBlockId, p: IKnownLicense): Promise<KnownLicenseEntity> {
  95. const record = await db.get(KnownLicenseEntity, { where: { id } })
  96. if (record) return record
  97. const knownLicence = new KnownLicenseEntity()
  98. knownLicence.id = id
  99. knownLicence.code = p.code
  100. knownLicence.name = p.name
  101. knownLicence.description = p.description
  102. knownLicence.url = p.url
  103. knownLicence.version = block
  104. knownLicence.happenedIn = await createBlockOrGetFromDatabase(db, block)
  105. await db.save(knownLicence)
  106. return knownLicence
  107. }
  108. async function createUserDefinedLicense(
  109. { db, block, id }: IDBBlockId,
  110. p: IUserDefinedLicense
  111. ): Promise<UserDefinedLicenseEntity> {
  112. const record = await db.get(UserDefinedLicenseEntity, { where: { id } })
  113. if (record) return record
  114. const userDefinedLicense = new UserDefinedLicenseEntity()
  115. userDefinedLicense.id = id
  116. userDefinedLicense.content = p.content
  117. userDefinedLicense.version = block
  118. userDefinedLicense.happenedIn = await createBlockOrGetFromDatabase(db, block)
  119. await db.save<UserDefinedLicenseEntity>(userDefinedLicense)
  120. return userDefinedLicense
  121. }
  122. async function createJoystreamMediaLocation(
  123. { db, block, id }: IDBBlockId,
  124. p: IJoystreamMediaLocation
  125. ): Promise<JoystreamMediaLocationEntity> {
  126. const record = await db.get(JoystreamMediaLocationEntity, { where: { id } })
  127. if (record) return record
  128. const joyMediaLoc = new JoystreamMediaLocationEntity()
  129. joyMediaLoc.id = id
  130. joyMediaLoc.dataObjectId = p.dataObjectId
  131. joyMediaLoc.version = block
  132. joyMediaLoc.happenedIn = await createBlockOrGetFromDatabase(db, block)
  133. await db.save(joyMediaLoc)
  134. return joyMediaLoc
  135. }
  136. async function createHttpMediaLocation(
  137. { db, block, id }: IDBBlockId,
  138. p: IHttpMediaLocation
  139. ): Promise<HttpMediaLocationEntity> {
  140. const record = await db.get(HttpMediaLocationEntity, { where: { id } })
  141. if (record) return record
  142. const httpMediaLoc = new HttpMediaLocationEntity()
  143. httpMediaLoc.id = id
  144. httpMediaLoc.url = p.url
  145. httpMediaLoc.port = p.port
  146. httpMediaLoc.version = block
  147. httpMediaLoc.happenedIn = await createBlockOrGetFromDatabase(db, block)
  148. await db.save(httpMediaLoc)
  149. return httpMediaLoc
  150. }
  151. async function createVideoMedia(
  152. { db, block, id }: IDBBlockId,
  153. classEntityMap: ClassEntityMap,
  154. p: IVideoMedia,
  155. nextEntityIdBeforeTransaction: number
  156. ): Promise<VideoMedia> {
  157. const videoMedia = new VideoMedia()
  158. videoMedia.id = id
  159. videoMedia.pixelHeight = p.pixelHeight
  160. videoMedia.pixelWidth = p.pixelWidth
  161. videoMedia.size = p.size
  162. videoMedia.version = block
  163. const { encoding, location } = p
  164. if (encoding !== undefined) {
  165. videoMedia.encoding = await getOrCreate.videoMediaEncoding(
  166. { db, block, id },
  167. classEntityMap,
  168. encoding,
  169. nextEntityIdBeforeTransaction
  170. )
  171. }
  172. if (location !== undefined) {
  173. const m = await getOrCreate.mediaLocation(
  174. { db, block, id },
  175. classEntityMap,
  176. location,
  177. nextEntityIdBeforeTransaction
  178. )
  179. videoMedia.locationEntity = m
  180. const { httpMediaLocation, joystreamMediaLocation } = m
  181. if (httpMediaLocation) {
  182. const mediaLoc = new HttpMediaLocation()
  183. mediaLoc.isTypeOf = 'HttpMediaLocation'
  184. mediaLoc.port = httpMediaLocation.port
  185. mediaLoc.url = httpMediaLocation.url
  186. videoMedia.location = mediaLoc
  187. }
  188. if (joystreamMediaLocation) {
  189. const mediaLoc = new JoystreamMediaLocation()
  190. mediaLoc.isTypeOf = 'JoystreamMediaLocation'
  191. mediaLoc.dataObjectId = joystreamMediaLocation.dataObjectId
  192. videoMedia.location = mediaLoc
  193. }
  194. }
  195. videoMedia.happenedIn = await createBlockOrGetFromDatabase(db, block)
  196. await db.save<VideoMedia>(videoMedia)
  197. return videoMedia
  198. }
  199. async function createVideo(
  200. { db, block, id }: IDBBlockId,
  201. classEntityMap: ClassEntityMap,
  202. p: IVideo,
  203. nextEntityIdBeforeTransaction: number
  204. ): Promise<Video> {
  205. const record = await db.get(Video, { where: { id } })
  206. if (record) return record
  207. const video = new Video()
  208. video.id = id
  209. video.title = p.title
  210. video.description = p.description
  211. video.duration = p.duration
  212. video.hasMarketing = p.hasMarketing
  213. // TODO: needs to be handled correctly, from runtime CurationStatus is coming
  214. video.isCurated = p.isCurated || true
  215. video.isExplicit = p.isExplicit
  216. video.isPublic = p.isPublic
  217. video.publishedBeforeJoystream = p.publishedBeforeJoystream
  218. video.skippableIntroDuration = p.skippableIntroDuration
  219. video.thumbnailUrl = p.thumbnailUrl
  220. video.version = block
  221. const { language, license, category, channel, media } = p
  222. if (language !== undefined) {
  223. video.language = await getOrCreate.language(
  224. { db, block, id },
  225. classEntityMap,
  226. language,
  227. nextEntityIdBeforeTransaction
  228. )
  229. }
  230. if (license !== undefined) {
  231. const { knownLicense, userdefinedLicense } = await getOrCreate.license(
  232. { db, block, id },
  233. classEntityMap,
  234. license,
  235. nextEntityIdBeforeTransaction
  236. )
  237. if (knownLicense) {
  238. const lic = new KnownLicense()
  239. lic.code = knownLicense.code
  240. lic.description = knownLicense.description
  241. lic.isTypeOf = 'KnownLicense'
  242. lic.name = knownLicense.name
  243. lic.url = knownLicense.url
  244. video.license = lic
  245. }
  246. if (userdefinedLicense) {
  247. const lic = new UserDefinedLicense()
  248. lic.content = userdefinedLicense.content
  249. lic.isTypeOf = 'UserDefinedLicense'
  250. video.license = lic
  251. }
  252. }
  253. if (category !== undefined) {
  254. video.category = await getOrCreate.category(
  255. { db, block, id },
  256. classEntityMap,
  257. category,
  258. nextEntityIdBeforeTransaction
  259. )
  260. }
  261. if (channel !== undefined) {
  262. video.channel = await getOrCreate.channel({ db, block, id }, classEntityMap, channel, nextEntityIdBeforeTransaction)
  263. }
  264. if (media !== undefined) {
  265. video.media = await getOrCreate.videoMedia({ db, block, id }, classEntityMap, media, nextEntityIdBeforeTransaction)
  266. }
  267. video.happenedIn = await createBlockOrGetFromDatabase(db, block)
  268. await db.save<Video>(video)
  269. return video
  270. }
  271. async function createLanguage({ db, block, id }: IDBBlockId, p: ILanguage): Promise<Language> {
  272. const record = await db.get(Language, { where: { id } })
  273. if (record) return record
  274. const language = new Language()
  275. language.id = id
  276. language.name = p.name
  277. language.code = p.code
  278. language.version = block
  279. language.happenedIn = await createBlockOrGetFromDatabase(db, block)
  280. await db.save<Language>(language)
  281. return language
  282. }
  283. async function createVideoMediaEncoding(
  284. { db, block, id }: IDBBlockId,
  285. p: IVideoMediaEncoding
  286. ): Promise<VideoMediaEncoding> {
  287. const record = await db.get(VideoMediaEncoding, { where: { id } })
  288. if (record) return record
  289. const encoding = new VideoMediaEncoding()
  290. encoding.id = id
  291. encoding.name = p.name
  292. encoding.version = block
  293. encoding.happenedIn = await createBlockOrGetFromDatabase(db, block)
  294. await db.save<VideoMediaEncoding>(encoding)
  295. return encoding
  296. }
  297. async function createLicense(
  298. { db, block, id }: IDBBlockId,
  299. classEntityMap: ClassEntityMap,
  300. p: ILicense,
  301. nextEntityIdBeforeTransaction: number
  302. ): Promise<LicenseEntity> {
  303. const record = await db.get(LicenseEntity, { where: { id } })
  304. if (record) return record
  305. const { knownLicense, userDefinedLicense } = p
  306. const license = new LicenseEntity()
  307. license.id = id
  308. if (knownLicense !== undefined) {
  309. license.knownLicense = await getOrCreate.knownLicense(
  310. { db, block, id },
  311. classEntityMap,
  312. knownLicense,
  313. nextEntityIdBeforeTransaction
  314. )
  315. }
  316. if (userDefinedLicense !== undefined) {
  317. license.userdefinedLicense = await getOrCreate.userDefinedLicense(
  318. { db, block, id },
  319. classEntityMap,
  320. userDefinedLicense,
  321. nextEntityIdBeforeTransaction
  322. )
  323. }
  324. license.happenedIn = await createBlockOrGetFromDatabase(db, block)
  325. await db.save<LicenseEntity>(license)
  326. return license
  327. }
  328. async function createMediaLocation(
  329. { db, block, id }: IDBBlockId,
  330. classEntityMap: ClassEntityMap,
  331. p: IMediaLocation,
  332. nextEntityIdBeforeTransaction: number
  333. ): Promise<MediaLocationEntity> {
  334. const { httpMediaLocation, joystreamMediaLocation } = p
  335. const location = new MediaLocationEntity()
  336. location.id = id
  337. if (httpMediaLocation !== undefined) {
  338. location.httpMediaLocation = await getOrCreate.httpMediaLocation(
  339. { db, block, id },
  340. classEntityMap,
  341. httpMediaLocation,
  342. nextEntityIdBeforeTransaction
  343. )
  344. }
  345. if (joystreamMediaLocation !== undefined) {
  346. location.joystreamMediaLocation = await getOrCreate.joystreamMediaLocation(
  347. { db, block, id },
  348. classEntityMap,
  349. joystreamMediaLocation,
  350. nextEntityIdBeforeTransaction
  351. )
  352. }
  353. location.happenedIn = await createBlockOrGetFromDatabase(db, block)
  354. await db.save<MediaLocationEntity>(location)
  355. return location
  356. }
  357. async function getClassName(
  358. db: DB,
  359. entity: IEntity,
  360. createEntityOperations: ICreateEntityOperation[]
  361. ): Promise<string | undefined> {
  362. const { entityId, indexOf } = entity
  363. if (entityId === undefined && indexOf === undefined) {
  364. throw Error(`Can not determine class of the entity`)
  365. }
  366. let classId: number | undefined
  367. // Is newly created entity in the same transaction
  368. if (indexOf !== undefined) {
  369. classId = createEntityOperations[indexOf].classId
  370. } else {
  371. const ce = await db.get(ClassEntity, { where: { id: entityId } })
  372. if (ce === undefined) console.log(`Class not found for the entity: ${entityId}`)
  373. classId = ce ? ce.classId : undefined
  374. }
  375. const c = contentDirectoryClassNamesWithId.find((c) => c.classId === classId)
  376. // TODO: stop execution, class should be created before entity creation
  377. if (c === undefined) console.log(`Not recognized class id: ${classId}`)
  378. return c ? c.name : undefined
  379. }
  380. export {
  381. createCategory,
  382. createChannel,
  383. createVideoMedia,
  384. createVideo,
  385. createUserDefinedLicense,
  386. createKnownLicense,
  387. createHttpMediaLocation,
  388. createJoystreamMediaLocation,
  389. createLanguage,
  390. createVideoMediaEncoding,
  391. createLicense,
  392. createMediaLocation,
  393. createBlockOrGetFromDatabase,
  394. getClassName,
  395. }