create.ts 12 KB

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