get-or-create.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. import { Channel } from '../../generated/graphql-server/src/modules/channel/channel.model'
  2. import { Category } from '../../generated/graphql-server/src/modules/category/category.model'
  3. import { KnownLicenseEntity } from '../../generated/graphql-server/src/modules/known-license-entity/known-license-entity.model'
  4. import { UserDefinedLicenseEntity } from '../../generated/graphql-server/src/modules/user-defined-license-entity/user-defined-license-entity.model'
  5. import { JoystreamMediaLocationEntity } from '../../generated/graphql-server/src/modules/joystream-media-location-entity/joystream-media-location-entity.model'
  6. import { HttpMediaLocationEntity } from '../../generated/graphql-server/src/modules/http-media-location-entity/http-media-location-entity.model'
  7. import { VideoMedia } from '../../generated/graphql-server/src/modules/video-media/video-media.model'
  8. import { Language } from '../../generated/graphql-server/src/modules/language/language.model'
  9. import { VideoMediaEncoding } from '../../generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.model'
  10. import { LicenseEntity } from '../../generated/graphql-server/src/modules/license-entity/license-entity.model'
  11. import { MediaLocationEntity } from '../../generated/graphql-server/src/modules/media-location-entity/media-location-entity.model'
  12. import { NextEntityId } from '../../generated/graphql-server/src/modules/next-entity-id/next-entity-id.model'
  13. import { decode } from './decode'
  14. import {
  15. categoryPropertyNamesWithId,
  16. channelPropertyNamesWithId,
  17. httpMediaLocationPropertyNamesWithId,
  18. joystreamMediaLocationPropertyNamesWithId,
  19. knownLicensePropertyNamesWIthId,
  20. languagePropertyNamesWIthId,
  21. licensePropertyNamesWithId,
  22. mediaLocationPropertyNamesWithId,
  23. userDefinedLicensePropertyNamesWithId,
  24. videoMediaEncodingPropertyNamesWithId,
  25. videoPropertyNamesWithId,
  26. } from './content-dir-consts'
  27. import {
  28. ClassEntityMap,
  29. ICategory,
  30. IChannel,
  31. IDBBlockId,
  32. IEntity,
  33. IHttpMediaLocation,
  34. IJoystreamMediaLocation,
  35. IKnownLicense,
  36. ILanguage,
  37. ILicense,
  38. IMediaLocation,
  39. IReference,
  40. IUserDefinedLicense,
  41. IVideoMedia,
  42. IVideoMediaEncoding,
  43. } from '../types'
  44. import {
  45. createCategory,
  46. createChannel,
  47. createVideoMedia,
  48. createUserDefinedLicense,
  49. createKnownLicense,
  50. createHttpMediaLocation,
  51. createJoystreamMediaLocation,
  52. createLanguage,
  53. createVideoMediaEncoding,
  54. createLicense,
  55. createMediaLocation,
  56. } from './entity/create'
  57. import { DB } from '../../generated/indexer'
  58. // Keep track of the next entity id
  59. async function nextEntityId(db: DB, nextEntityId: number): Promise<void> {
  60. let e = await db.get(NextEntityId, { where: { id: '1' } })
  61. if (!e) e = new NextEntityId({ id: '1' })
  62. e.nextId = nextEntityId
  63. await db.save<NextEntityId>(e)
  64. }
  65. function generateEntityIdFromIndex(index: number): string {
  66. return `${index}`
  67. }
  68. function findEntity(entityId: number, className: string, classEntityMap: ClassEntityMap): IEntity {
  69. const newlyCreatedEntities = classEntityMap.get(className)
  70. if (newlyCreatedEntities === undefined) throw Error(`Couldn't find '${className}' entities in the classEntityMap`)
  71. const entity = newlyCreatedEntities.find((e) => e.indexOf === entityId)
  72. if (!entity) throw Error(`Unknown ${className} entity id: ${entityId}`)
  73. // Remove the inserted entity from the list
  74. classEntityMap.set(
  75. className,
  76. newlyCreatedEntities.filter((e) => e.entityId !== entityId)
  77. )
  78. return entity
  79. }
  80. async function language(
  81. { db, block }: IDBBlockId,
  82. classEntityMap: ClassEntityMap,
  83. language: IReference,
  84. nextEntityIdBeforeTransaction: number
  85. ): Promise<Language> {
  86. let lang
  87. const { entityId, existing } = language
  88. if (existing) {
  89. lang = await db.get(Language, { where: { id: entityId.toString() } })
  90. if (!lang) throw Error(`Language entity not found`)
  91. return lang
  92. }
  93. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  94. // could be created in the transaction
  95. lang = await db.get(Language, { where: { id } })
  96. if (lang) return lang
  97. // get the entity from list of newly created entities and insert into db
  98. const { properties } = findEntity(entityId, 'Language', classEntityMap)
  99. return await createLanguage(
  100. { db, block, id },
  101. decode.setEntityPropertyValues<ILanguage>(properties, languagePropertyNamesWIthId)
  102. )
  103. }
  104. async function videoMediaEncoding(
  105. { db, block }: IDBBlockId,
  106. classEntityMap: ClassEntityMap,
  107. encoding: IReference,
  108. nextEntityIdBeforeTransaction: number
  109. ): Promise<VideoMediaEncoding> {
  110. let vmEncoding
  111. const { entityId, existing } = encoding
  112. if (existing) {
  113. vmEncoding = await db.get(VideoMediaEncoding, { where: { id: entityId.toString() } })
  114. if (!vmEncoding) throw Error(`VideoMediaEncoding entity not found`)
  115. return vmEncoding
  116. }
  117. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  118. // could be created in the transaction
  119. vmEncoding = await db.get(VideoMediaEncoding, { where: { id } })
  120. if (vmEncoding) return vmEncoding
  121. const { properties } = findEntity(entityId, 'VideoMediaEncoding', classEntityMap)
  122. return await createVideoMediaEncoding(
  123. { db, block, id },
  124. decode.setEntityPropertyValues<IVideoMediaEncoding>(properties, videoMediaEncodingPropertyNamesWithId)
  125. )
  126. }
  127. async function videoMedia(
  128. { db, block }: IDBBlockId,
  129. classEntityMap: ClassEntityMap,
  130. media: IReference,
  131. nextEntityIdBeforeTransaction: number
  132. ): Promise<VideoMedia> {
  133. let videoM: VideoMedia | undefined
  134. const { entityId, existing } = media
  135. if (existing) {
  136. videoM = await db.get(VideoMedia, { where: { id: entityId.toString() } })
  137. if (!videoM) throw Error(`VideoMedia entity not found`)
  138. return videoM
  139. }
  140. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  141. // could be created in the transaction
  142. videoM = await db.get(VideoMedia, { where: { id } })
  143. if (videoM) return videoM
  144. const { properties } = findEntity(entityId, 'VideoMedia', classEntityMap)
  145. return await createVideoMedia(
  146. { db, block, id },
  147. classEntityMap,
  148. decode.setEntityPropertyValues<IVideoMedia>(properties, videoPropertyNamesWithId),
  149. nextEntityIdBeforeTransaction
  150. )
  151. }
  152. async function knownLicense(
  153. { db, block }: IDBBlockId,
  154. classEntityMap: ClassEntityMap,
  155. knownLicense: IReference,
  156. nextEntityIdBeforeTransaction: number
  157. ): Promise<KnownLicenseEntity> {
  158. let kLicense: KnownLicenseEntity | undefined
  159. const { entityId, existing } = knownLicense
  160. if (existing) {
  161. kLicense = await db.get(KnownLicenseEntity, { where: { id: entityId.toString() } })
  162. if (!kLicense) throw Error(`KnownLicense entity not found`)
  163. return kLicense
  164. }
  165. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  166. // could be created in the transaction
  167. kLicense = await db.get(KnownLicenseEntity, { where: { id } })
  168. if (kLicense) return kLicense
  169. const { properties } = findEntity(entityId, 'KnownLicense', classEntityMap)
  170. return await createKnownLicense(
  171. { db, block, id },
  172. decode.setEntityPropertyValues<IKnownLicense>(properties, knownLicensePropertyNamesWIthId)
  173. )
  174. }
  175. async function userDefinedLicense(
  176. { db, block }: IDBBlockId,
  177. classEntityMap: ClassEntityMap,
  178. userDefinedLicense: IReference,
  179. nextEntityIdBeforeTransaction: number
  180. ): Promise<UserDefinedLicenseEntity> {
  181. let udLicense: UserDefinedLicenseEntity | undefined
  182. const { entityId, existing } = userDefinedLicense
  183. if (existing) {
  184. udLicense = await db.get(UserDefinedLicenseEntity, { where: { id: entityId.toString() } })
  185. if (!udLicense) throw Error(`UserDefinedLicense entity not found`)
  186. return udLicense
  187. }
  188. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  189. // could be created in the transaction
  190. udLicense = await db.get(UserDefinedLicenseEntity, {
  191. where: { id },
  192. })
  193. if (udLicense) return udLicense
  194. const { properties } = findEntity(entityId, 'UserDefinedLicense', classEntityMap)
  195. return await createUserDefinedLicense(
  196. { db, block, id },
  197. decode.setEntityPropertyValues<IUserDefinedLicense>(properties, userDefinedLicensePropertyNamesWithId)
  198. )
  199. }
  200. async function channel(
  201. { db, block }: IDBBlockId,
  202. classEntityMap: ClassEntityMap,
  203. channel: IReference,
  204. nextEntityIdBeforeTransaction: number
  205. ): Promise<Channel> {
  206. let chann: Channel | undefined
  207. const { entityId, existing } = channel
  208. if (existing) {
  209. chann = await db.get(Channel, { where: { id: entityId.toString() } })
  210. if (!chann) throw Error(`Channel entity not found`)
  211. return chann
  212. }
  213. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  214. // could be created in the transaction
  215. chann = await db.get(Channel, { where: { id } })
  216. if (chann) return chann
  217. const { properties } = findEntity(entityId, 'Channel', classEntityMap)
  218. return await createChannel(
  219. { db, block, id },
  220. classEntityMap,
  221. decode.setEntityPropertyValues<IChannel>(properties, channelPropertyNamesWithId),
  222. nextEntityIdBeforeTransaction
  223. )
  224. }
  225. async function category(
  226. { db, block }: IDBBlockId,
  227. classEntityMap: ClassEntityMap,
  228. category: IReference,
  229. nextEntityIdBeforeTransaction: number
  230. ): Promise<Category> {
  231. let cat: Category | undefined
  232. const { entityId, existing } = category
  233. if (existing) {
  234. cat = await db.get(Category, { where: { id: entityId.toString() } })
  235. if (!cat) throw Error(`Category entity not found`)
  236. return cat
  237. }
  238. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  239. // could be created in the transaction
  240. cat = await db.get(Category, { where: { id } })
  241. if (cat) return cat
  242. const { properties } = findEntity(entityId, 'Category', classEntityMap)
  243. return await createCategory(
  244. { db, block, id },
  245. decode.setEntityPropertyValues<ICategory>(properties, categoryPropertyNamesWithId)
  246. )
  247. }
  248. async function httpMediaLocation(
  249. { db, block }: IDBBlockId,
  250. classEntityMap: ClassEntityMap,
  251. httpMediaLoc: IReference,
  252. nextEntityIdBeforeTransaction: number
  253. ): Promise<HttpMediaLocationEntity | undefined> {
  254. let loc: HttpMediaLocationEntity | undefined
  255. const { entityId, existing } = httpMediaLoc
  256. if (existing) {
  257. loc = await db.get(HttpMediaLocationEntity, { where: { id: entityId.toString() } })
  258. if (!loc) throw Error(`HttpMediaLocation entity not found`)
  259. return loc
  260. }
  261. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  262. // could be created in the transaction
  263. loc = await db.get(HttpMediaLocationEntity, {
  264. where: { id },
  265. })
  266. if (loc) return loc
  267. const { properties } = findEntity(entityId, 'HttpMediaLocation', classEntityMap)
  268. return await createHttpMediaLocation(
  269. { db, block, id },
  270. decode.setEntityPropertyValues<IHttpMediaLocation>(properties, httpMediaLocationPropertyNamesWithId)
  271. )
  272. }
  273. async function joystreamMediaLocation(
  274. { db, block }: IDBBlockId,
  275. classEntityMap: ClassEntityMap,
  276. joyMediaLoc: IReference,
  277. nextEntityIdBeforeTransaction: number
  278. ): Promise<JoystreamMediaLocationEntity | undefined> {
  279. let loc: JoystreamMediaLocationEntity | undefined
  280. const { entityId, existing } = joyMediaLoc
  281. if (existing) {
  282. loc = await db.get(JoystreamMediaLocationEntity, { where: { id: entityId.toString() } })
  283. if (!loc) throw Error(`JoystreamMediaLocation entity not found`)
  284. return loc
  285. }
  286. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  287. // could be created in the transaction
  288. loc = await db.get(JoystreamMediaLocationEntity, {
  289. where: { id },
  290. })
  291. if (loc) return loc
  292. const { properties } = findEntity(entityId, 'JoystreamMediaLocation', classEntityMap)
  293. return await createJoystreamMediaLocation(
  294. { db, block, id },
  295. decode.setEntityPropertyValues<IJoystreamMediaLocation>(properties, joystreamMediaLocationPropertyNamesWithId)
  296. )
  297. }
  298. async function license(
  299. { db, block }: IDBBlockId,
  300. classEntityMap: ClassEntityMap,
  301. license: IReference,
  302. nextEntityIdBeforeTransaction: number
  303. ): Promise<LicenseEntity> {
  304. let lic: LicenseEntity | undefined
  305. const { entityId, existing } = license
  306. if (existing) {
  307. lic = await db.get(LicenseEntity, { where: { id: entityId.toString() } })
  308. if (!lic) throw Error(`License entity not found`)
  309. return lic
  310. }
  311. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  312. // could be created in the transaction
  313. lic = await db.get(LicenseEntity, { where: { id } })
  314. if (lic) return lic
  315. const { properties } = findEntity(entityId, 'License', classEntityMap)
  316. return await createLicense(
  317. { db, block, id },
  318. classEntityMap,
  319. decode.setEntityPropertyValues<ILicense>(properties, licensePropertyNamesWithId),
  320. nextEntityIdBeforeTransaction
  321. )
  322. }
  323. async function mediaLocation(
  324. { db, block }: IDBBlockId,
  325. classEntityMap: ClassEntityMap,
  326. location: IReference,
  327. nextEntityIdBeforeTransaction: number
  328. ): Promise<MediaLocationEntity> {
  329. let loc: MediaLocationEntity | undefined
  330. const { entityId, existing } = location
  331. if (existing) {
  332. loc = await db.get(MediaLocationEntity, { where: { id: entityId.toString() } })
  333. if (!loc) throw Error(`MediaLocation entity not found`)
  334. return loc
  335. }
  336. const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
  337. // could be created in the transaction
  338. loc = await db.get(MediaLocationEntity, {
  339. where: { id },
  340. relations: ['httpMediaLocation', 'joystreamMediaLocation'],
  341. })
  342. if (loc) {
  343. return loc
  344. }
  345. const { properties } = findEntity(entityId, 'MediaLocation', classEntityMap)
  346. return await createMediaLocation(
  347. { db, block, id },
  348. classEntityMap,
  349. decode.setEntityPropertyValues<IMediaLocation>(properties, mediaLocationPropertyNamesWithId),
  350. nextEntityIdBeforeTransaction
  351. )
  352. }
  353. export const getOrCreate = {
  354. language,
  355. videoMediaEncoding,
  356. videoMedia,
  357. knownLicense,
  358. userDefinedLicense,
  359. channel,
  360. category,
  361. joystreamMediaLocation,
  362. httpMediaLocation,
  363. license,
  364. mediaLocation,
  365. nextEntityId,
  366. }