get-or-create.ts 14 KB

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